haskell hlist hnil pattern matching hfoldl -
i've been trying code work data.hlist. know can need adt alone wanted see how work hlist experimenting. i'm having trouble compiling code wrote.
{-# language gadts #-} module testhlist import data.hlist.commonmain data mytype1 = mytype1 { x::int, y::int } deriving (show) data mytype2 = mytype2 { text::string, slen::int } deriving (show) data mytype3 = mytype3 { dval1::int, dval2::string } deriving (show) test1 = hcons (mytype2 { text = "hello", slen=5 }) (hcons (mytype1 { x=1, y=2 }) (hcons (mytype3 { dval1=3, dval2="world" }) hnil)) test2 = hcons (mytype1 { x=4, y=5 }) (hcons (mytype1 { x=6, y=7 }) (hcons (mytype2 { text="again.", slen=6 }) hnil)) addtype1 ls1 ls2 = happendlist ls1 ls2 class mytypesint sumit :: -> int instance mytypesint mytype1 sumit val = (x val) + (y val) instance mytypesint mytype2 sumit val = slen val instance mytypesint mytype3 sumit val = (dval1 val) * 2 sumtest1 v = sumit v sumtest2 ls = sumit (hhead ls) foldtest ls = hfoldl (\(v1,v2) -> v1 + (sumit v2)) 0 ls sumtest3 = foldtest test1 sumall hnil = 0 sumall ls = (sumit (hhead ls)) + (sumall (htail ls)) {- sumall3 xs | xs == hnil = 0 | otherwise = (sumit (hhead xs)) + (sumall3 (htail xs)) -}
the code doesn't useful it's intended me understand how use hlist. code declares 3 separate data types , makes class , defines instances 3 types. goal setup list , execute class function, sumit, on each element of list based on instance defined them. know test1, test2 addtype1, sumtest1 , sumtest2 work. compile errors foldtest , sumall functions. think need define function declarations not sure how. here compile errors.
testhlist.hs:39:1: not deduce (mytypesint a0) arising ambiguity check `foldtest' context (num z, hfoldl ((int, a) -> int) z xs r, mytypesint a) bound inferred type `foldtest': (num z, hfoldl ((int, a) -> int) z xs r, mytypesint a) => hlist xs -> r @ testhlist.hs:39:1-55 type variable `a0' ambiguous possible fix: add type signature fixes these type variable(s) note: there several potential instances: instance mytypesint mytype3 -- defined @ testhlist.hs:33:10 instance mytypesint mytype2 -- defined @ testhlist.hs:30:10 instance mytypesint mytype1 -- defined @ testhlist.hs:27:10 when checking `foldtest' has inferred type `forall z (xs :: [*]) r a. (num z, hfoldl ((int, a) -> int) z xs r, mytypesint a) => hlist xs -> r' probable cause: inferred type ambiguous testhlist.hs:42:8: couldn't match type `(':) * e0 l0' '[] * inaccessible code in pattern constructor hnil :: hlist ('[] *), in equation `sumall' in pattern: hnil in equation `sumall': sumall hnil = 0 testhlist.hs:43:49: occurs check: cannot construct infinite type: l0 = (':) * e0 l0 expected type: hlist ((':) * e0 ((':) * e0 l0)) actual type: hlist ((':) * e0 l0) in first argument of `htail', namely `ls' in first argument of `sumall', namely `(htail ls)' in second argument of `(+)', namely `(sumall (htail ls))'
my question know need fix code work? i've done quite few searches find answer. it's possible i've seen answer during search i'm not understanding it.
thanks
update:
while researching ideas in answers given ran across link: http://en.wikibooks.org/wiki/haskell/existentially_quantified_types
after reading easy implement trying do. i'm not changing answer. question how code work data.hlist , answers provided well. intention figure out how setup , use heterogeneous list , thought @ time data.hlist way it. following code bit easier me follow, wanted provide in case else finds useful.
{-# language existentialquantification #-} module testheterlist data mytype1 = mytype1 { x::int, y::int } deriving (show) data mytype2 = mytype2 { text::string, slen::int } deriving (show) data mytype3 = mytype3 { dval1::int, dval2::string } deriving (show) class mytypesint sumit :: -> int instance mytypesint mytype1 sumit val = (x val) + (y val) instance mytypesint mytype2 sumit val = slen val instance mytypesint mytype3 sumit val = (dval1 val) * 2 data genelem = forall s. (show s, mytypesint s) => ge s instance show genelem show (ge s) = show s test1 :: [genelem] test1 = [ge (mytype2 { text = "hello", slen=5 }), ge (mytype1 { x=1, y=2 }), ge (mytype3 { dval1=3, dval2="world" })] foldtest xs = foldl (\acc (ge val) -> acc + sumit val) (0::int) xs sumtest1 = foldtest test1 sumall [] = 0 sumall (ge v : xs) = (sumit v) + (sumall xs) sumtest2 = sumall test1
here's how can make hfoldl
-based variant work:
data hsumall = hsumall instance (mytypesint a, int ~ int) => applyab hsumall (int, a) int applyab hsumall (v1, v2) = v1 + sumit v2 foldtest ls = hfoldl hsumall (0 :: int) ls sumtest3 = foldtest test1
making direct version work more tricky. first of all, have use pattern matching, because hlist
gadt, , type refinement can't possibly work if use selector functions. furthermore, functions matching on gadts need explicit type signatures. end this:
sumall :: hlist ls -> int -- wrong sumall hnil = 0 sumall (hcons x xs) = sumit x + sumall xs
this produces following type error:
could not deduce
(mytypesint e)
arising use of`sumit'
context(ls ~ (':) * e l1)
...
and ghc of course right complain. need all types in ls
instance of mytypesint
. i've browsed hlist package see if library provides way express this, seems me doesn't. fortunately, relatively easy these days (requires constraintkinds
, importing ghc.exts
access constraint
):
type family (c :: * -> constraint) (xs :: [*]) :: constraint type instance c '[] = () type instance c (x ': xs) = (c x, c xs)
then can say:
sumall :: mytypesint ls => hlist ls -> int sumall hnil = 0 sumall (hcons x xs) = sumit x + sumall xs
this typechecks , works expected.
Comments
Post a Comment