Will Clarke

# Function Composition is super cool

2021-08-19

Function composition is kind of important - especially in functional languages.

I recently was trying to do something in Haskell where I wanted to do a kind of “deep” `map`.

The function `map` has the type signature of

``````Prelude> :t map
map :: (a -> b) -> [a] -> [b]``````

What I wanted was:

``notSureHowToImplement :: (a -> b) -> [[a]] -> [[b]]``

I scrabbled around doing hacky and ugly things… until I realised that we should be able to use the default `map` function by calling it twice:

``````Prelude> :t (map . map)
map :: (a -> b) -> [[a]] -> [[b]]``````

But how does it work?

This trick relies on some deep and mysterious secrets which functional programming is build upon: currying & composition.

If you eyeball the `map` function again, what it’s actually doing is taking a function and then returning another function that operates on a list to create another list:

``````Prelude> :t map
map :: (a -> b) -> [a] -> [b]
-- can be written like:
-- map :: (a -> b) -> ([a] -> [b])``````

The fact that `map` takes a function and returns a function means that… we can use `map` on `map`’s output function…

A reminder about function composition: Function composition is just calling functions:

``h(x) = g(f(x))``

In haskell this is so important that its operator is just “`.`”.

``````Prelude> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c``````

so `(map . map) f` is the same as `map (map f )`

Here’s the function in practice:

``````Prelude> (map . map) (* 2) [[1,2,3],[4,5]]
[[2,4,6],[8,10]]``````

Isn’t it lovely?