有人可以向我解释为什么我的concat实现中的源列表类型不起作用?
conc::[[a]]->[a]
conc xs@(x1:xs')=foldr (:) [] xs
为什么源列表应为[a]
而不是[[a]]
?如果我想连续[[1,2],[3,4]]
不是[[a]]
类型而不是[a]
,而元素类型是[a]
。
我收到以下错误:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for:
conc :: forall a. [[a]] -> [a]
答案 0 :(得分:4)
实际上编译器会在错误中显示有用的提示(实际上比您发布的消息低几行)
Expected type: [a]
Actual type: [[a]]
在下面的代码中,参数确实是[[a]]
类型,但结果也是类型[[a]]
,它与类型定义冲突:
conc :: [[a]] -> [a]
conc xs@(x1:xs') = foldr (:) [] xs
代码中的 xs
类型为[[a]]
,您使用foldr
对其进行迭代,并将每个[a]
类型的元素添加到列表中。因此,您会收到[[a]]
类型的列表。
答案 1 :(得分:1)
foldr (:) [] xs == xs
, True
为xs
。这意味着foldr (:) []
是列表上的标识函数。这个事实众所周知,是Haskell绝杀的一部分,以至于foldr (:) []
在经验丰富的Haskell程序员的脑海中自动读作id
。
查看foldr c n
的一种方法是将“cons”(即(:)
)替换为c
,将[]
替换为n
。名单。将(:)
替换为(:)
而将[]
替换为[]
显然不会改变任何内容:
[a, b, ..., z] ==> a : b : ... : z : [] == [a, b, ..., z]
另一方面用(:)
替换(++)
,将输入列表中的所有列表连接成一个:
[a, b, ..., z] ==> a ++ b ++ ... ++ z
这是你想要实现的目标。
因此concat
foldr
的正确实施是foldr (++) []
。