0

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
4
  • Why are you asking? Commented Apr 19, 2018 at 19:25
  • 2
    (\(k, v) -> (k, v)) doesn't do anything. It seems you forgot to use f there. Commented Apr 19, 2018 at 19:26
  • Well the compiler gives an error. Usually that is a good starting point to debug. Commented Apr 19, 2018 at 19:26
  • You are applying f to k instead of v. Commented Apr 20, 2018 at 7:14

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

3 Comments

is it possible to apply the function on the key?
@barnabasmarkus: no, since Functor f, expects an f with one type parameter, and here that is the value. You can of course redesign it, and define a Map v k, such that you can fmap on the values, but not the way the Map is currently defined.
thanks a lot! that was my original question, but somehow I have made a mistake when I posted here!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.