What's the problem w this Functor
instance?
data Map k v = Map [(k, v)] deriving (Show, Eq)
instance Functor (Map a) where
fmap _ (Map []) = Map []
fmap f (Map xs) = Map xs'
where xs' = map (\(k, v) -> (f k, v)) xs
If we compile this, we get the error:
<interactive>:6:21: error:
• Couldn't match type ‘a1’ with ‘b’
‘a1’ is a rigid type variable bound by
the type signature for:
fmap :: forall a1 b. (a1 -> b) -> Map a a1 -> Map a b
at <interactive>:5:3
‘b’ is a rigid type variable bound by
the type signature for:
fmap :: forall a1 b. (a1 -> b) -> Map a a1 -> Map a b
at <interactive>:5:3
Expected type: Map a b
Actual type: Map a a1
• In the expression: Map xs'
In an equation for ‘fmap’:
fmap f (Map xs)
= Map xs'
where
xs' = map (\ (k, v) -> (k, v)) xs
In the instance declaration for ‘Functor (Map a)’
• Relevant bindings include
xs' :: [(a, a1)] (bound at <interactive>:7:11)
xs :: [(a, a1)] (bound at <interactive>:6:15)
f :: a1 -> b (bound at <interactive>:6:8)
fmap :: (a1 -> b) -> Map a a1 -> Map a b
(bound at <interactive>:5:3)
The error actually is a good starting point: it says that your fmap
should have signature:
fmap :: forall a1 b. (a1 -> b) -> Map a a1 -> Map a b
but apparently your output type is Map a a1
, so you did not met these contracts. If we further investigate, we see that map (\(k, v) -> (k, v)) xs
actually does not do much (except repacking the data in a new tuple). The output tuple should have type (a, b)
instead of (a, a1)
(a1
being the original type of the values in the Map
).
We thus should apply f
on the value, like:
instance Functor (Map a) where
fmap _ (Map []) = Map []
fmap f (Map xs) = Map xs'
where xs' = map (\(k, v) -> (k, f v)) xs
or in a more clean way:
instance Functor (Map a) where
fmap f (Map xs) = Map (fmap (fmap f) xs)
Note that you do not need to implement two separate cases here (one for an empty and one for a non-empty list), since a map
(or fmap
) on an empty list is an empty list.