Point-free code is ubiquitous in every well-polished Hackage library. It’s more concise than its pointed counterparts and feels more “hygienic” as function composition immediately translates to its mathematical background.
1 2 3 |
|
So far, so good. However, you get a problem in your chain of function composition when your right-most function “takes two parameters”.
1 2 3 4 5 6 7 8 |
|
Unfortunately, coolSolution
is not well-typed; this might drive you
nuts for some time: It’s obvious that composing those functions must
somehow work. You’d think: “Even GHCI must have understood what I
mean!” However, Haskell doesn’t care for what you mean as much as it
cares for type-safety ;) ! So you might fall back on boringSolution
which is only half the fun as it’s not point-free… anyway, there IS
a way to compose those functions!
In the following I will use
Typed holes. They are a nice tool to look into the type checker’s
“thoughts”.
Well, first have a look at why coolSolution
did not type-check at all.
1 2 3 4 5 |
|
Essentially, this tells us that plusOne
does not have the right type
to be used together with (. readTwoArgs)
. Now let’s ask this
question to the type checker: What do I need to apply to plusOne
so
that you are happy?
1
|
|
The answer we get is:
1 2 3 4 5 6 |
|
Okay, this help us. Our “hole function”’s type is (Int -> Int) ->
(String -> Int) -> [Char] -> Int
. Now we just write that
function – actually, the type signature and our knowledge of what
should be the result of the whole expression give rise to that unique holeFunction
:
1 2 3 4 5 6 |
|
By (re)writing it in a point-free style and by applying eta-reductions we
get a very simple definition. It turns out that our holeFunction
is
just ordinary function composition^^. Anyway, let’s have a look if that works.
1 2 3 |
|
Yes, it does! That “.).” looks funny and will surely confuse everybody whose doesn’t know that “trick” (and does not have a type-checker in their brain). However, it gets even funnier. When your right-most function expects even more arguments you just add ‘a couple of’ “.)”s in between!
1 2 |
|
Conclusion
Thus, we have found a way to use the (point-free) function composition even when you need to feed more than a single argument into it!
As point-free code is more concise it can be clearer about what you want to do, however, it can obfuscate your intentions as well! (Look at those combinators). In the case of this ((x.).) trick, I think it can still be beneficial if and only if everybody in your team “knows the trick” and does not have to think about it. The nice reason is: As soon as you delete that “.)” chain mentally you immediately grasp the meaning of the resulting function!