haskell hlist hnil模式匹配hfoldl(haskell hlist hnil pattern matching hfoldl)

编程入门 行业动态 更新时间:2024-10-24 18:21:42
haskell hlist hnil模式匹配hfoldl(haskell hlist hnil pattern matching hfoldl)

我一直在试图获得一些代码来处理Data.HList。 我知道我可以单独做ADT所需要的,但我想看看它如何与HList合作,所以我正在试验。 但是我在编写我写的代码时遇到了麻烦。

{-# LANGUAGE GADTs #-} module TestHList where 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 a where sumIt :: a -> Int instance MyTypesInt MyType1 where sumIt val = (x val) + (y val) instance MyTypesInt MyType2 where sumIt val = slen val instance MyTypesInt MyType3 where 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)) -}

代码没有做任何有用的事情,它只是为了帮助我理解如何使用HList。 该代码声明了3个独立的数据类型,并为这3个类型定义了一个类并定义了实例。 我的目标是设置一个列表,然后根据为它们定义的实例在列表的每个元素上执行类函数sumIt。 我知道test1,test2 addType1,sumTest1和sumTest2的工作。 我得到的编译错误是针对foldTest和sumAll函数的。 我想我需要定义函数声明,但不知道如何。 这里是编译错误。

TestHList.hs:39:1: Could not deduce (MyTypesInt a0) arising from the ambiguity check for `foldTest' from the context (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) bound by the inferred type for `foldTest': (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) => HList xs -> r at TestHList.hs:39:1-55 The type variable `a0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance MyTypesInt MyType3 -- Defined at TestHList.hs:33:10 instance MyTypesInt MyType2 -- Defined at TestHList.hs:30:10 instance MyTypesInt MyType1 -- Defined at TestHList.hs:27:10 When checking that `foldTest' has the inferred type `forall z (xs :: [*]) r a. (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) => HList xs -> r' Probable cause: the inferred type is ambiguous TestHList.hs:42:8: Couldn't match type `(':) * e0 l0' with '[] * Inaccessible code in a pattern with constructor HNil :: HList ('[] *), in an equation for `sumAll' In the pattern: HNil In an equation for `sumAll': sumAll HNil = 0 TestHList.hs:43:49: Occurs check: cannot construct the infinite type: l0 = (':) * e0 l0 Expected type: HList ((':) * e0 ((':) * e0 l0)) Actual type: HList ((':) * e0 l0) In the first argument of `hTail', namely `ls' In the first argument of `sumAll', namely `(hTail ls)' In the second argument of `(+)', namely `(sumAll (hTail ls))'

我的问题是有人知道我需要做什么来修复代码,所以它会工作? 我做了不少搜索找到答案。 在搜索过程中我可能看到了答案,但我只是不理解它。

谢谢

更新:

在研究答案中的想法时,我得到了以下链接: http : //en.wikibooks.org/wiki/Haskell/Existentially_quantified_types

阅读完这些后,很容易实现我正在尝试做的事情。 我没有改变答案。 我的问题是关于如何让我的代码与Data.HList一起工作,并且提供的答案做得非常好。 但我的意图是想出如何设置和使用异构列表,我当时认为Data.HList是实现它的方式。 下面的代码对我来说更容易一些,所以我想提供它以防其他人发现它有用。

{-# LANGUAGE ExistentialQuantification #-} module TestHeterList where 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 a where sumIt :: a -> Int instance MyTypesInt MyType1 where sumIt val = (x val) + (y val) instance MyTypesInt MyType2 where sumIt val = slen val instance MyTypesInt MyType3 where sumIt val = (dval1 val) * 2 data GenElem = forall s. (Show s, MyTypesInt s) => GE s instance Show GenElem where 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

I've been trying to get some code to work with Data.HList. I know I can do what I need to with ADT alone but I wanted to see how it would work with HList so I was experimenting. But I'm having trouble compiling code I wrote.

{-# LANGUAGE GADTs #-} module TestHList where 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 a where sumIt :: a -> Int instance MyTypesInt MyType1 where sumIt val = (x val) + (y val) instance MyTypesInt MyType2 where sumIt val = slen val instance MyTypesInt MyType3 where 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 do anything useful it's only intended to help me understand how to use HList. The code declares 3 separate data types and makes a class and defines instances for the 3 types. My goal was to setup a list and then execute the class function, sumIt, over each element of the list based on the instance defined for them. I know test1, test2 addType1, sumTest1 and sumTest2 work. The compile errors I get are for the foldTest and sumAll functions. I think I need to define function declarations but not sure how. Here are the compile errors.

TestHList.hs:39:1: Could not deduce (MyTypesInt a0) arising from the ambiguity check for `foldTest' from the context (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) bound by the inferred type for `foldTest': (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) => HList xs -> r at TestHList.hs:39:1-55 The type variable `a0' is ambiguous Possible fix: add a type signature that fixes these type variable(s) Note: there are several potential instances: instance MyTypesInt MyType3 -- Defined at TestHList.hs:33:10 instance MyTypesInt MyType2 -- Defined at TestHList.hs:30:10 instance MyTypesInt MyType1 -- Defined at TestHList.hs:27:10 When checking that `foldTest' has the inferred type `forall z (xs :: [*]) r a. (Num z, HFoldl ((Int, a) -> Int) z xs r, MyTypesInt a) => HList xs -> r' Probable cause: the inferred type is ambiguous TestHList.hs:42:8: Couldn't match type `(':) * e0 l0' with '[] * Inaccessible code in a pattern with constructor HNil :: HList ('[] *), in an equation for `sumAll' In the pattern: HNil In an equation for `sumAll': sumAll HNil = 0 TestHList.hs:43:49: Occurs check: cannot construct the infinite type: l0 = (':) * e0 l0 Expected type: HList ((':) * e0 ((':) * e0 l0)) Actual type: HList ((':) * e0 l0) In the first argument of `hTail', namely `ls' In the first argument of `sumAll', namely `(hTail ls)' In the second argument of `(+)', namely `(sumAll (hTail ls))'

My question is does someone know what I need to do to fix the code so it would work? I've done quite a few searches to find the answer. It's possible I've seen the answer during that search but that I'm just not understanding it.

Thanks

Update:

While researching the ideas in the answers I was given I ran across this link: http://en.wikibooks.org/wiki/Haskell/Existentially_quantified_types

After reading this it was easy to implement what I was trying to do. I'm not changing the answer. My question was specifically about how to get my code to work with Data.HList and the answers provided do that very well. But my intention was to figure out how to setup and use a heterogeneous list and I thought at the time Data.HList was the way to do it. The following code is a bit easier for me to follow, so I wanted to provide it in case someone else finds it useful.

{-# LANGUAGE ExistentialQuantification #-} module TestHeterList where 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 a where sumIt :: a -> Int instance MyTypesInt MyType1 where sumIt val = (x val) + (y val) instance MyTypesInt MyType2 where sumIt val = slen val instance MyTypesInt MyType3 where sumIt val = (dval1 val) * 2 data GenElem = forall s. (Show s, MyTypesInt s) => GE s instance Show GenElem where 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

最满意答案

以下是您如何制作基于hFoldl的变体作品:

data HSumAll = HSumAll instance (MyTypesInt a, int ~ Int) => ApplyAB HSumAll (Int, a) int where applyAB HSumAll (v1, v2) = v1 + sumIt v2 foldTest ls = hFoldl HSumAll (0 :: Int) ls sumTest3 = foldTest test1

使直接版本工作更加棘手。 首先,你必须使用模式匹配,因为HList是一个GADT,如果你使用选择器函数,类型细化不可能工作。 此外,在GADT上匹配的函数需要显式类型签名。 所以你最终会得到这样的结果:

sumAll :: HList ls -> Int -- WRONG sumAll HNil = 0 sumAll (HCons x xs) = sumIt x + sumAll xs

这会产生以下类型的错误:

无法推断(MyTypesInt e)由上下文中使用`sumIt'引起的(MyTypesInt e) (ls ~ (':) * e l1) ...

GHC当然有权投诉。 我们需要ls 所有类型成为MyTypesInt一个实例。 我浏览过HList软件包,看看图书馆是否提供了一种表达方式,但在我看来,它没有。 幸运的是,这些日子相对比较简单(需要ConstraintKinds并导入GHC.Exts才能访问Constraint ):

type family All (c :: * -> Constraint) (xs :: [*]) :: Constraint type instance All c '[] = () type instance All c (x ': xs) = (c x, All c xs)

然后你可以说:

sumAll :: All MyTypesInt ls => HList ls -> Int sumAll HNil = 0 sumAll (HCons x xs) = sumIt x + sumAll xs

这种类型检测和按预期工作。

Here's how you can make the hFoldl-based variant work:

data HSumAll = HSumAll instance (MyTypesInt a, int ~ Int) => ApplyAB HSumAll (Int, a) int where applyAB HSumAll (v1, v2) = v1 + sumIt v2 foldTest ls = hFoldl HSumAll (0 :: Int) ls sumTest3 = foldTest test1

Making the direct version work is more tricky. First of all, you have to use pattern matching, because HList is a GADT, and the type refinement can't possibly work if you use selector functions. Furthermore, functions matching on GADTs need explicit type signatures. So you end up with something like this:

sumAll :: HList ls -> Int -- WRONG sumAll HNil = 0 sumAll (HCons x xs) = sumIt x + sumAll xs

This produces the following type error:

Could not deduce (MyTypesInt e) arising from a use of `sumIt' from the context (ls ~ (':) * e l1) ...

And GHC is of course right to complain. We need all the types in ls to be an instance of MyTypesInt. I've browsed the HList package to see if the library provides a way to express this, but it seems to me it doesn't. Fortunately, this is relatively easy to do these days (requires ConstraintKinds and importing GHC.Exts to get access to Constraint):

type family All (c :: * -> Constraint) (xs :: [*]) :: Constraint type instance All c '[] = () type instance All c (x ': xs) = (c x, All c xs)

Then you can say:

sumAll :: All MyTypesInt ls => HList ls -> Int sumAll HNil = 0 sumAll (HCons x xs) = sumIt x + sumAll xs

This typechecks and works as expected.

更多推荐

本文发布于:2023-07-04 16:54:00,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1026876.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:模式   hnil   hlist   haskell   pattern

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!