为什么我的自定义类型的地图实现不正确?

我正在从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

Listmap的自然实现将区分您在类型声明中给出的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

链接地址: http://www.djcxy.com/p/43039.html

上一篇: Why is my implementation of a map on a custom type not correct?

下一篇: Type signature is too general; missing constraint?