[英]Algebraic data type list into an actual list
我想创建一个函数,在其中输入一个代数数据类型列表,它应该输出一个实际列表。
例如,我们有一个list1 = P `Cons` (G `Cons` Empty)
输出应为: [G,P]
我创建了以下代数数据类型:
data Elements = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Elements (List Elements)
我当前的功能是:
list:: Elements -> [List]
list Empty = []
list Cons a (List b) = [a] ++ list (List b)
我在解决这个问题时遇到了麻烦,如果能得到一些帮助,我将不胜感激!
提前致谢!
让我们从您的数据类型开始:
data Elements = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Elements (List Elements)
从技术角度来看, Elements
没有任何问题,但它是一个非常糟糕的名称选择。 正如其他人所指出的,命名类型Element
更为常见。 原因是你的数据类型声明的英文翻译是:
“元素”是黄金或白银或铂金。
什么时候说:
“元素”是金或银或铂金
此外,当您开始使用这种类型编写代码时,它会开始变得混乱。 如果您定义Elements
类型的值:
e :: Elements
e = P
这代表单个元素“白金”,而不是集合元素。 这种混淆可能会导致您使用错误的类型签名编写list
函数,因为您认为您是在说list
采用一堆Elements
,但类型签名实际上表示list
只采用一个元素。
出于这个原因,我将搜索并替换您的所有代码,我的其余答案将使用“ Element
”来讨论这个版本:
data Element = G | S | P deriving (Eq, Show)
data List a = Empty | Cons Element (List Element)
list:: Element -> [List]
list Empty = []
list Cons a (List b) = [a] ++ list (List b)
list1 = P `Cons` (G `Cons` Empty)
继续,您的List
类型有问题:
data List a = Empty | Cons Element (List Element)
您已经定义了一个参数化类型List a
,但是您还没有在其定义中使用参数a
。 在您看到List a
定义的其他情况下,这是因为a
参数应该表示列表项的类型,因此可以使用相同的列表来保存Element
s 或Int
s 或其他任何内容。 由于您需要一个仅包含Element
的特殊列表数据类型,因此您应该编写不带参数的List
(在此声明的左侧和右侧):
data List = Empty | Cons Element List
^^- no "a" ^^- no "Element" argument
现在,考虑list
的类型签名:
list :: Element -> [List]
list
应该做的是获取一个元素列表,例如:
list1 = P `Cons` (G `Cons` Empty)
并生成一个 Haskell 列表作为结果:
result1 = [G,P]
但是这个类型签名说list
将采用单个Element
并生成一个 Haskell 列表,其项目是List
类型(即,一个自定义的Element
List
),换句话说,它将生成一个 List 的List
元素。 这肯定是不对的。
事实上, list
应该采用Element
的List
并返回Element
的(Haskell)列表,因此类型签名应为:
list :: List -> [Element]
请注意,如果您仅将类型声明加载到 GHCi 中并检查示例参数和结果的类型:
ghci> data Element = G | S | P deriving (Eq, Show)
ghci> data List = Empty | Cons Element List
ghci> :type P `Cons` (G `Cons` Empty)
P `Cons` (G `Cons` Empty) :: List -- input is of type `List`
ghci> :type [G,P]
[G,P] :: [Element] -- output is of type `[Element]`
这将确认您需要一个函数List -> [Element]
。
现在,您的定义还有两个错误:
list Cons a (List b) = [a] ++ list (List b)
像Cons a (List b)
这样的模式需要用括号括起来以匹配单个参数,所以这应该是:
list (Cons a (List b)) = [a] ++ list (List b)
这里还有一个问题。 List
的使用在这里没有意义。 List
是一种类型,它属于类型签名,而不属于模式或表达式,至少不是这样。 Haskell 已经知道Cons
的第二个字段是一个List
,所以你不需要告诉它。 您只需要将该字段分配给一个变量。 如果你从两边删除List
:
list (Cons a b) = [a] ++ list b
最终定义应该进行类型检查:
list :: List -> [Element]
list Empty = []
list (Cons a b) = [a] ++ list b
如果您想要倒序的结果,只需翻转连接即可:
list :: List -> [Element]
list Empty = []
list (Cons a b) = list b ++ [a]
最终代码:
data Element = G | S | P deriving (Eq, Show)
data List = Empty | Cons Element List deriving (Show)
list:: List -> [Element]
list Empty = []
list (Cons a b) = list b ++ [a]
list1 = P `Cons` (G `Cons` Empty)
main = print $ list list1 -- output [G,P]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.