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