为什么我的自定义类型的地图实现不正确?
我正在从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
以上给出了以下错误:
无法与实际类型'List t0'匹配预期类型'b''b'是由map ::(a - > b) - > List a - > List b类型签名绑定的刚性类型变量
我试图达到以下目的:
>>> map (+10) (1 :. 2 :. 3 :. Nil)
[11,12,13]
首先,解释错误消息:因为你不能在你的定义中使用filter
filter :: (a -> Bool) -> [a] -> [a]
必须处理普通的Prelude列表,而不是你的List
- 即[a]
不List a
。 错误信息出现,因为filter
期望a
map f a = filter (listElement -> listElement /= Nil) a
成为某种东西的列表,但您提供的签名声明a
是某物的List
。 类似地, filter
返回一个Prelude的东西列表,但签名要求它返回一个List
。
List
的map
的自然实现将区分您在类型声明中给出的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
for 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)
这个函数做的是从List列表中删除空元素,比如Prelude.filter (not . Prelude.null)
。 同样,您定义的实际功能(没有签名)会从列表的Prelude列表中删除Nil
列表。
filter (listElement -> listElement /= Nil) a
这是类型错误的来源。 如果你的执行filter
遵循合理的路径, listElement
应的元素a
,那就是,因为a
具有类型List a
,它的类型为a
。 您将它与Nil
进行比较,其类型为List a
。
上一篇: Why is my implementation of a map on a custom type not correct?