#
`map`

and `fmap`

in Haskell

Haskell’s standard module ships with two functions, called `map`

and
`fmap`

. The first one, `map`

, is the typical function we are all used to in
functional programming. Looking at its definition, reveals that it’s recursive
implementation is exactly what one would expect:

1 2 3 | map :: (a -> b) -> [a] -> [b] map _ [] = [] map f (x:xs) = f x : map f xs |

Based on `foldr`

, we can write an identical function with an even shorter
defintion:

1 2 | map' :: (a -> b) -> [a] -> [b] map' f = foldr ( (:) . f ) [] |

It’s important to avoid tail recursion, because that would make lazy
evaluation impossible, which is a prerequisite for dealing with infinite
lists. That’s why `foldl`

is a bad idea, even though it would be faster
(assuming the compiler performs tail call optimization).

In addition to `map`

, there’s the `Functor`

class, whose instances are required
to implement `fmap`

:

1 2 | class Functor (f :: * -> *) where fmap :: (a -> b) -> f a -> f b |

As it turns out, `[]`

is an instance of `Functor`

:

1 2 | instance Functor [] where fmap = map |

So, at least for lists, there’s no difference between the two. However, there
are many more `Functor`

instances. For example, let’s examine the instance for
`Maybe`

:

1 2 3 | instance Functor Maybe where fmap _ Nothing = Nothing fmap f (Just a) = Just (f a) |

If the value we are mapping over is `Nothing`

, it returns `Nothing`

. Otherwise,
it’s applying the given function `f`

to the value from the `Just`

and returns
another `Just`

with `f`

’s return value.

Personally, this reminds me of ActiveSupport’s `Object#try`

method. The
`Functor`

instance for `Maybe`

is encapsulating exactly the same pattern, but in
a more abstract way. That’s because the implementation can be completely
different for other types.

The bottom line is that `fmap`

is a generalized version of `map`

. You can `fmap`

whatever you want, as long as there’s a `Functor`

instance for its type. This
is extremely powerful, because it allows us to push complexity from the caller
to the callee.

From now on, I’m going to use `fmap`

exclusively in my own code: Code that’s
using more generalized functions is easier to reuse and change later on.