{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module HListExample.MainPosting051106 where
-- Needed for a reply to the Haskell mailing list
import Data.HList.CommonMain hiding (Comp(..))
import Properties.Common
import Test.Hspec
mainPosting051106 = describe "hComposeList (a -> H[a -> b,b -> c,c -> d] -> d)" $ do
it "defined here" $
comp "abc" `shouldShowTo` "8"
it "defined in HList" $
hComposeList test2 "abc" `shouldShowTo` "8"
test = HCons (length::String -> Int) (HCons ((+1)::(Int->Int)) (HCons ((*2)::(Int->Int)) HNil))
test2 = length .*. (+1) .*. (*2) .*. HNil
data Comp
{- simpler class. wouldn't work with test2. The original HFoldr won't work with
- Apply anymore.
instance Apply Comp (x -> y,y -> z)
where
type ApplyR Comp (x -> y,y -> z) = x -> z
apply _ (f,g) = g . f
-}
-- `~` is (built-in) TypeCast mentioned below
instance ((x -> y,y -> z) ~ xyz, (x -> z) ~ xz)
=> ApplyAB Comp xyz xz
where
applyAB _ (f,g) = g . f
-- Function composition based on type code works.
comp = hFoldr (undefined::Comp) (id::Int -> Int) test
-- Function composition based on normal polymorphism doesn't
-- comp' = hFoldr (uncurry (flip (.))) (id::Int -> Int) test
{-
From Ralf.Lammel at microsoft.com Mon Nov 7 00:11:01 2005
From: Ralf.Lammel at microsoft.com (Ralf Lammel)
Date: Sun Nov 6 23:50:27 2005
Subject: [Haskell-cafe] Type classes and hFoldr from HList
Message-ID: <1152E22EE8996742A7E36BBBA7768FEE079C474F@RED-MSG-50.redmond.corp.microsoft.com>
Hi Greg,
Since hfoldr is right-associative, I prefer to reorder your list of
functions as follows:
> test = HCons (length::String -> Int) (HCons ((+1)::(Int->Int)) (HCons
((*2)::(Int->Int)) HNil))
Note that I also annotated length with its specific type.
(If you really wanted to leave things more polymorphic, you would need
to engage in TypeCast.)
Providing a specific Apply instance for (.) is not necessary, strictly
necessary. We could try to exploit the normal function instance for
Apply.
Let me recall that one here for convenience:
>instance Apply (x -> y) x y
> where
> apply f x = f x
Let me also recall the hFoldr instances:
>class HList l => HFoldr f v l r | f v l -> r
> where
> hFoldr :: f -> v -> l -> r
>instance HFoldr f v HNil v
> where
> hFoldr _ v _ = v
>instance ( HFoldr f v l r
> , Apply f (e,r) r'
> )
> => HFoldr f v (HCons e l) r'
> where
> hFoldr f v (HCons e l) = apply f (e,hFoldr f v l)
To fit in (.), we would flip and uncurry it.
So we could try:
comp' = hFoldr (uncurry (flip (.))) (id::Int -> Int) test
This wouldn't work.
The trouble is the required polymorphism of the first argument of
hFoldr.
The type of that argument as such is polymorphic.
However, this polymorphism does not survive type class parameterization.
You see this by looking at the HCons instance of HFoldr.
The different occurrences of "f" would need to be used at different
types.
This would only work if the type class parameter f were instantiated by
the polymorphic type of (uncurry (flip (.))). (And even then we may need
something like TypeCast.)
What you can do is define a dedicated *type code* for composition.
comp = hFoldr (undefined::Comp) (id::Int -> Int) test
data Comp
instance Apply Comp (x -> y,y -> z) (x -> z)
where
apply _ (f,g) = g . f
Ralf
> -----Original Message-----
> From: haskell-cafe-bounces@haskell.org [mailto:haskell-cafe-
> bounces@haskell.org] On Behalf Of Greg Buchholz
> Sent: Sunday, November 06, 2005 7:01 PM
> To: haskell-cafe@haskell.org
> Subject: [Haskell-cafe] Type classes and hFoldr from HList
>
>
> I was playing around with the HList library from the paper...
>
> Strongly typed heterogeneous collections
> http://homepages.cwi.nl/~ralf/HList/
>
> ...and I thought I'd try to fold the composition function (.) through
a
> heterogeneous list of functions, using hFoldr...
>
> >{-# OPTIONS -fglasgow-exts #-}
> >{-# OPTIONS -fallow-undecidable-instances #-}
> >
> >import CommonMain
> >
> >main = print $ comp "abc"
> >
> >test = HCons ((+1)::(Int->Int)) (HCons ((*2)::(Int->Int)) (HCons
length
> HNil))
> >
> >comp = hFoldr (.) id test
> >
> >instance Apply (a -> b -> c -> d) (a, b) (c -> d)
> > where
> > apply f (a,b) = f a b
>
> ...but it fails with the following type error...
>
> ]Compiling Main ( compose.hs, interpreted )
> ]
> ]compose.hs:10:7:
> ] No instances for (Apply ((b -> c) -> (a -> b) -> a -> c)
> ] (Int -> Int, r)
> ] ([Char] -> a3),
> ] Apply ((b -> c) -> (a -> b) -> a -> c) (Int ->
Int,
> r1) r,
> ] Apply ((b -> c) -> (a -> b) -> a -> c) ([a2] ->
> Int, a1 ->a1) r1)
> ] arising from use of `hFoldr' at compose.hs:10:7-12
> ] Probable fix:
> ] add an instance declaration for (Apply ((b -> c) -> (a -> b) ->
a -
> > c)
> ] (Int -> Int, r)
> ] ([Char] -> a3),
> ] Apply ((b -> c) -> (a -> b) ->
a -
> > c)
> ](Int -> Int, r1) r,
> ] Apply ((b -> c) -> (a -> b) ->
a -
> > c)
> ]([a2] -> Int, a1 -> a1) r1)
> ] In the definition of `comp': comp = hFoldr (.) id test
>
> ...Anyway, I couldn't quite tell whether I was using hFoldr
incorrectly,
> or if I needed to have more constraints placed on the construction of
> "test", or if needed some sort of type-level function that resolves...
>
> Apply ((b -> c) -> (a -> b) -> a -> c)
>
> ...into (a -> c), or something else altogether. I figured someone
might
> be able to help point me in the right direction.
-}