我跟随https://github.com/NICTA/course
进行了List练习以下代码段从https://github.com/NICTA/course/blob/master/src/Course/List.hs
的一部分复制而来data List t =
Nil
| t :. List t
deriving (Eq, Ord)
map ::
(a -> b)
-> List a
-> List b
map f a = filter (\listElement -> listElement /= Nil) a
以上给出了以下错误:
无法将预期类型'b'与实际类型匹配'列表t0''b'是由map ::(a - > b)的类型签名绑定的刚性类型变量 - >列出一个 - >列表b
我试图实现以下目标:
>>> map (+10) (1 :. 2 :. 3 :. Nil)
[11,12,13]
答案 0 :(得分:5)
首先,解释错误消息:您的定义中不能使用filter
,因为
filter :: (a -> Bool) -> [a] -> [a]
与常规Prelude列表有关,而不是List
s - 即[a]
而不是List a
。出现错误消息是因为filter
期望
a
map f a = filter (\listElement -> listElement /= Nil) a
是一个列表,但你提供的签名声明a
是List
的东西。类似地,filter
返回某事物的Prelude列表,但签名要求它返回List
某事物。
map
的{{1}}的自然实现会区分您在类型声明中提供的List
的情况,即它会“模式匹配”:
List
请注意,您编写的程序完全有效,只是与您提供的签名冲突:
mapList ::
(a -> b)
-> List a
-> List b
mapList f Nil = Nil
mapList f (t :. ls) = f t :. mapList f ls
ghci> let mapX f a = filter (\listElement -> listElement /= Nil) a
ghci> :t mapX
mapX :: Eq a => t -> [List a] -> [List a]
约束是必需的,因为你预先假定Eq
被测试是否相等,因此它们的元素可以被测试。我没有使用List
,所以它最终只是一个'可能是任何东西'参数,在这里f
。
当然,如果您拥有t
filterList
的{{1}},那么它也会出现问题
List
此函数的作用是从列表列表中删除空元素,例如ghci> let filterList pred Nil = Nil; filterList pred (a :. as) = if pred a then a :. filterList pred as else filterList pred as
ghci> :t filterList
filterList :: (t -> Bool) -> List t -> List t
ghci> let mapY f a = filterList (\listElement -> listElement /= Nil) a
ghci> :t mapY
mapY :: Eq a => t -> List (List a) -> List (List a)
。同样,您定义的实际功能(没有签名)从列表的 Prelude列表中删除了Prelude.filter (not . Prelude.null)
列表。
答案 1 :(得分:1)
filter (\listElement -> listElement /= Nil) a
这是类型错误的来源。如果filter
的实施遵循合理的路径,则listElement
应该是a
的元素,也就是说,因为a
的类型为List a
,所以它是类型a
。您将不平等与Nil
类型List a
进行比较。