Today I stumpled upon a very nice and concise (but quite hard to understand) point-free implementation of Pascals-Triangle in Haskell:

import Control.Applicative^{1)}<*> pascal :: [[Int]] pascal = iterate newrow [1] where newrow = (zipWith (+) <*> tail) . (0:) . (++[0])

let’s first confirm that this really works (…*magic*):

λ> take 5 $ pascal [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]

Seems to work.

## But how …

Of course I know how to get a pascals triangle and I don’t have a problem with `iterate`

.

But the usage of *applicative* in `newrow`

(together with some doubt about precedence of function application and `<*>`

)

made this very short snippet quite hard to understand for me.

So let’s flesh out `newrow`

out a bit:

newrow = (zipWith (+) <*> tail) . (0:) . (++[0]) == newrow =^{2)}zipWith (+ <*> tail) . (0:) . (++ [0])

The last two functions are easy: they just append and prepend a `0`

each, so if we look at the types we get:

λ> :t (0:) . (++[0]) (0:) . (++[0]) :: Num a => [a] -> [a]

and we are left with

(zipWith (+)) <*> tail

Now the *hard* part to understand is what instance of `Applicative`

we are

really using here – and it’s **not** `[]`

it’s `Num a => `

^{3)}->) [a])!
So the applicative instance are functions taking a list of numbers somewhere.
And now of course the types match niecely:
λ> :t ...continue -> ([a] -> [a]) -> ([a] -> [a])

`So what this really does is taking an row of numbers `

`row`

, prepends and appends a `0`

to it: `0:row++[0]`

.

And then it takes the tail of this and zips the two versions with `(+)`

: `zipWith (+) (row++[0]) (0:row++[0])`

.

```
```That’s it.

## why not just …

pascal :: [[Int]]
pascal = iterate newrow [1]
where newrow row = zipWith (+) (0:row) (row++[0])

This is in my opinion easier to read, needs fewer knowledge (don’t need to know about *applicatives*) and is even shorter!

The only difference is that this does not **force point-free** style down your throat.

Ok – I cheated a bit (because where is the point in making the list bigger on both sides if `zip`

and `tail`

only uses parts of it anyway).

But I think this is another good case of why sometimes *point-free* is indeed *pointless* and should be avoided to make your code more read- and understandable.

Remember: the next person that’s to stupid to understand your clever code is most likely *you in 2 months* 😀

References

1. ↑ <*> 2. ↑ zipWith (+ 3. ↑ ->) [a])!
So the applicative instance are **functions taking a list of numbers somewhere**.

And now of course the types match niecely:

λ> :t zipWith (+)
zipWith (+) :: Num a => [a] -> ([a] -> [a])
λ> :t tail
tail :: [a] -> [a]
λ> :t (<*>)
(<*>)
:: Num a => ([a] -> ([a] -> [a]