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
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
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
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
that you are happy?
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
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
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!
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!