I am reading the book "Programming in Haskell". One exercise asks me to define map f
using an higher-order function. I choose to define map (+1)
like the following:
unfold p h t x | p x = []
| otherwise = h x : unfold p h t (t x)
-- equivalent to `map (+1)`
mapinc = unfold (==[]) ((+1).head) tail
(Taken straight from the exercise question) The function unfold pht
produces the empty list if the predicate p
is true of the argument value, and otherwise produces a non-empty list by applying the function h
to this value to give the head, and the function t
to generate another argument that is recursively processed in the same way to produce the tail of the list.
I have checked my implementation of mapinc
and it looks fine:
*Main> mapinc [1,2,3]
[2,3,4]
However, after I add the type declaration:
mapinc :: Num a => [a] -> [a]
mapinc = unfold (==[]) ((+1).head) tail
Then reload the script in WinGHCi, it gives the following error:
• Could not deduce (Eq a) arising from a use of ‘==’
from the context: Num a
bound by the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
at D:\7a.hs:4:1-29
Possible fix:
add (Eq a) to the context of
the type signature for:
mapinc :: forall a. Num a => [a] -> [a]
• In the first argument of ‘unfold’, namely ‘(== [])’
In the expression: unfold (== []) ((+ 1) . head) tail
In an equation for ‘mapinc’:
mapinc = unfold (== []) ((+ 1) . head) tail
|
5 | mapinc = unfold (==[]) ((+1).head) tail | ^^^^
Any clue why it happens?
Your signature is too broad . The predicate you have written is == []
. Haskell can only check if two lists are equal, if the elements of the list can be checked as well. In the source code we see something like:
instance Eq [a] where
...
Yes, here we will never check the equality of two items, since we check with the empty list, but the compiler of course does not know that: it simply sees that in order to check whether two lists are equal, we need to be able to check if elements are equal.
The Num
typeclass does not imply that the type is also an Eq
type. We can do two things here:
add the Eq
type constraint to the signature:
mapinc :: Num a => [a] -> [a] mapinc = unfold (==[]) ((+1).head) tail
more elegant: do not rely on the fact that we need to be able to compare elements, but use null :: [a] -> Bool
instead (a function that checks if the list is empty):
mapinc :: Num a => [a] -> [a] mapinc = unfold ((+1).head) tail
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.