Why is my implementation of a map on a custom type not correct?
I'm following the List exercise from https://github.com/NICTA/course
The below snippet copied from part of 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
The above gives me the below error:
Couldn't match expected type 'b' with actual type 'List t0' 'b' is a rigid type variable bound by the type signature for map :: (a -> b) -> List a -> List b
I'm trying to achieve the below:
>>> map (+10) (1 :. 2 :. 3 :. Nil)
[11,12,13]
First, to explain the error message: you can't use filter in your definition, since
filter :: (a -> Bool) -> [a] -> [a]
has to do with regular Prelude lists, not your List s -- ie [a] not List a . The error message arises because filter expects a in
map f a = filter (listElement -> listElement /= Nil) a
to be a list of something, but the signature you supplied declares that a is a List of something. Similarly filter returns a Prelude list of something, but the signature requires that it return a List of something.
The natural implementation of map for List would distinguish the cases of List that you gave in the type declaration, that is, it would "pattern match":
mapList ::
(a -> b)
-> List a
-> List b
mapList f Nil = Nil
mapList f (t :. ls) = f t :. mapList f ls
Note that the program you wrote is perfectly valid, it just conflicts with the signature you gave it:
ghci> let mapX f a = filter (listElement -> listElement /= Nil) a
ghci> :t mapX
mapX :: Eq a => t -> [List a] -> [List a]
The Eq constraint is required because you presuppose that List s be tested for equality and thus that their elements can be. f is not used, so it just ends up as a 'could be anything' parameter, here t .
Of course, if you have your own filterList for List s it will also typecheck
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)
What this function does is delete null elements from a List of Lists, like Prelude.filter (not . Prelude.null) . Similarly, the actual function you defined (without the signature) deleted Nil Lists from a Prelude list of your Lists.
filter (listElement -> listElement /= Nil) a
Here's the source of type error. If your implementation of filter follows reasonable path, listElement should be an element of a , that is, since a has type List a , it is of type a . You compare it for inequality against Nil which is of type List a .
上一篇: 看起来正确的类型签名被拒绝在哪里
下一篇: 为什么我的自定义类型的地图实现不正确?
