# (((Wait a moment .) .) .) - Composing Functions with Multiple Arguments

Posted on March 13, 2021 by ubikium## Panel 1: Introduction

I saw this meme post in r/haskell about point-free Haskell the other day. It’s meant to be sarcastic, I know, but there are actually some good ideas in it. So I might as well write a blog.

Per the meme, there are four ways to define `mapM`

in terms of `sequence`

and `fmap`

. But actually, you only need to understand their definitions for Panel 1. All the rest can be derived from the first definition, each achieving the goal of point-free to some extent. For our purpose, let’s assume a function `composed :: a -> b -> d`

can be defined in terms of `f :: a -> b -> c`

and `g :: c -> d`

. If we explicitly write out the arguments, then we get the first panel:

```
composed :: a -> b -> d
f :: a -> b -> c
g :: c -> d
= g (f a b) composed a b
```

So our goal can be restated as: to compose `f`

and `g`

, we first accept two arguments, then pass them to `f`

, and finally forward the result to `g`

. Or we can say, we want to *wait for two arguments* before forwarding the result.

A more familiar case is when we just want to *wait for one argument*.

```
composed' :: a -> d
f' :: a -> c
g' :: c -> d
= g' (f' a) composed' a
```

In this case, we have the usual function composition operator

```
(.) :: (b -> c) -> (a -> b) -> (a -> c)
. f) a = g (f a) (g
```

Then it’s easy to see how we can make `composed'`

point-free:

```
= (g' . f') a
composed' a = g' . f' -- η reduction composed'
```

The problem, of course, is how to find a similar operator to wait for two arguments, or in general, wait for *n* arguments.

## Panel 2: `curry`

or `uncurry`

, that is the question!

`= curry (g . uncurry f) composed `

Panel 2 uses `curry`

and `uncurry`

to bundle the two arguments together into a pair, then wait for the bundle with `(.)`

. When passing the bundle to `f`

, we need to unbundle it.

Recall the definition of `curry`

and `uncurry`

:

```
curry :: ((a, b) -> c) -> (a -> b -> c)
uncurry :: (a -> b -> c) -> ((a, b) -> c)
```

Then we can derive Panel 2:

```
f :: a -> b -> c
uncurry f :: (a, b) -> c
g :: c -> d
. uncurry f :: (a, b) -> d
g curry (g . uncurry f) :: a -> b -> d
```

This works fine for waiting for two arguments, but it’s not a good example for point-free style or abstraction because it

- doesn’t separate the composition operator with the actual functions to be composed, they are instead intertwined together.
- doesn’t generalize well if we want to wait for three or more arguments, we need to implement
`curry3`

and`uncurry3`

.

Therefore, we can’t read the intention of the code well. It doesn’t directly express the idea of *waiting for two arguments*.

## Panel 3: Birds of a feather

`= (.).(.) g f composed `

The third panel seems promising, because it separates the operator and the functions, but what on earth is `(.).(.)`

? (spoiler: it’s not on earth!)

I tried very hard to understand it the first time I met it. My current best explanation is as follows:

Recall the partial application of `(.)`

, we have `(.) f ≡ (f .)`

(*).

At first, we have `(.).(.) g f`

, so when `(.).(.)`

gets the first argument `g`

, what does it do?

Since it’s a composition of two functions, it will pass `g`

to the latter function and forward the result to the former function.

That is `(secondF . firstF) g ≡ secondF (firstF g)`

. Here we take both `secondF`

and `firstF`

to be `(.)`

. Then

```
. firstF) g ≡ secondF (firstF g)
(secondF .) g)
≡ secondF ((.) -- see (*) above
≡ secondF (g .) (g .)
≡ (.) .) -- see (*) above ≡ ((g
```

Then we apply it to the second argument `f`

, we get `(.).(.) g f ≡ (g .) . f`

.

How can we understand `(g .) . f`

then?

Well, it’s a function composition. So when the first argument `a`

comes, it will be passed to `f`

, and the result will be forward to `(g .)`

.

```
.) . f $ a ≡ (g .) (f a)
(g . (f a) ≡ g
```

Then the second argument `b`

comes, what will it do? Oh, it is again a function composition, so we pass `b`

to the second function `(f a)`

, and then forward the result to `g`

.

```
. (f a) $ b ≡ g ((f a) b)
g ≡ g ( f a b)
```

We achieved our goal.

This can also be understood through the type signature. After the first argument `a`

comes to `(g .) . f`

, it will be passed to `f :: a -> b -> c`

, resulting in `f a :: b -> c`

. Then we can just compose it with `g :: c -> d`

with the usual `(.)`

.

So far, we have established that `(g .) . f`

will wait for two arguments. Also, we know `g . f`

will wait for one argument. Actually, these are special cases for a general pattern:

```
. f -- wait for 1 more argument
g .) . f -- wait for 2 more arguments
(g .) .) . f -- wait for 3 more arguments ((g
```

Or equivalently, the operator style:

```
.) -- wait for 1 more argument
(.).(.) -- wait for 2 more arguments
(.).(.).(.) -- wait for 3 more arguments (
```

The type signatures will tell us what they do:

```
(.) :: (d -> e) -> ( c -> d) -> ( c -> e)
.).(.) :: (d -> e) -> ( b -> c -> d) -> ( b -> c -> e)
(.).(.).(.) :: (d -> e) -> (a -> b -> c -> d) -> (a -> b -> c -> e) (
```

Although presented in a meme, these are actually quite useful and common higher-order operators. Once you know them, they’re pretty easy to read, remember, and write.

`(.).(.)`

is often presented as the first non-trivial example in these operators. It’s called a *blackbird* operator in Amar Shah’s talk about point-free, a *dot* in the Haskell wiki for point-free.

This family of operators is also an example for Semantic Editor Combinators in Edward Kmett’s talk about lenses.

## Panel 4: One of them is not like the others

`= fmap fmap fmap g f composed `

In Panel 3, there are three points. BUt i thOught wE weRE DOing poINT-FREe PROGrAmMINg! So for Panel 4, we have three `fmap`

and zero points. A reasonable guess would be that `fmap`

is secretly `(.)`

. But how?

Recall their definitions:

```
(.) :: (b -> c) -> (a -> b) -> (a -> c)
fmap :: Functor f => (b -> c) -> ( f b) -> ( f c)
```

So here, we are instantiating the functor `f`

to be `(a ->)`

. That is, we partially apply a fixed type `a`

to `(->)`

, and change the return type variable, resulting in a (covariant) functor.

This functor is known as the *Reader* functor. We can explicitly define it as `data Reader a x = Reader { runReader :: a -> x }`

. But in Haskell, we can just write `((->) a)`

.

You can verify that its functor instance must be

```
instance Functor ((->) a) where
fmap = (.)
```

You can read more about the Reader functor in this post from Bartosz’s blog.

Back to the meme, if we replace all `(.)`

with `fmap`

in Panel 3, then we get Panel 4.

It’s correct, but really confusing. Without looking at the signature, one can hardly imagine which instance is `fmap`

using, let alone the intention of three `fmap`

being together (the original meme also use `fmap`

as an argument, just to be fun!).

There is, however, a chance to salvage something from Panel 4. Let’s think `fmap fmap fmap`

in terms of itself, instead of being just `(.)`

in disguise.

One way to type check `fmap fmap fmap`

is to let the first `fmap`

be instantiated to the Reader functor `fmap`

, i.e. `(.)`

. Then `fmap fmap fmap`

becomes `(.) fmap fmap ≡ fmap . fmap`

.

The type signature can be derived as

```
fmap :: Functor f1 => (a -> b) -> (f1 a -> f1 b)
fmap :: Functor f2 => (c -> d ) -> (f2 c -> f2 d)
```

We can take `c`

to be `f1 a`

and `d`

to be `f1 b`

. Therefore

```
fmap :: Functor f1 => (a -> b) -> (f1 a -> f1 b)
fmap :: Functor f1 => (f1 a -> f1 b) -> f2 (f1 a) -> f2 (f1 b)
fmap . fmap :: (Functor f1, Functor f2) => (a -> b) -> f2 (f1 a) -> f2 (f1 b)
```

So by combining two `fmap`

, we get one functor level *deeper* into the structure. This is another example of Semantic Editor Combinators also mentioned in the Kmett talk. The general case is:

```
fmap :: (Functor f1) => (a -> b) -> f3 a -> f3 b
fmap . fmap :: (Functor f1, Functor f2) => (a -> b) -> f3 (f2 a) -> f3 (f2 b)
fmap . fmap . fmap :: (Functor f1, Functor f2, Functor f3) => (a -> b) -> f3 (f2 (f1 a)) -> f3 (f2 (f1 b))
```

We go one functor level deeper for each `fmap`

composed. Keep digging this way, then you might find some lens for yourself!

## Conclusion: What’s the point of point-free anyway?

The goal of the point-free style is the same as all other forms of abstraction: to express your intention in a *concise* (to write), *clear* (to read), and *general* (to change) way. All fore-mentioned methods can be summarized as follows:

Definition | Point-free | Concise | Clear | General |
---|---|---|---|---|

`composed a b = g (f a b)` |
X | X | O | X |

`composed = curry (g . uncurry f)` |
O | X | X | X |

`composed = (.).(.) g f` |
O | O | O* | O* |

`composed = fmap fmap fmap g f` |
O | O | X | O* |

`composed = (fmap . fmap) g f` |
O | O | O* | O* |

(*): some experience required

Conclusions:

- If you need clarity and don’t want to surprise others, go for Panel 1, write all arguments explicitly:
`composed a b = g (f a b)`

. - Not every point-free change is guaranteed to be an improvement. You should avoid Panel 2 style (point-free for the sake of point-free) as much as possible. A point-free change should have a strong semantic encoding.
- For Panel 3 and modified Panel 4, we can see the power of good point-free usage. We find a pattern (
`(.).(.)`

and`fmap . fmap`

) with almost all of the advantages. However, they might be difficult to understand for those who are unfamiliar. And it takes a great deal of efforts to find a new one. Therefore, it’s good for in-house use. - For the original Panel 4, try not to hide your intention. Replace some instances of
`fmap`

with its concrete instance to avoid repetition and ambiguity (even just for humans).

Edit notes:

- The
`(.).(.)`

is called a*blackbird*, a special kind of bird. That is to say, it’s a special case of an operator in a family of operators. Thanks for Jean-Baptiste Mazon to point it out.