haskellfunctional-programmingpointfree

When can a pointful function be refactored to be point free?


What are the conditions on a function of arbitrary number of arguments such that it is able to be refactored to be point free? Is it trivial look at a pointful representation of a function and determine whether it is possible to refactor it to be point free?

I would assume the conditions are language agnostic to some degree, but if not I am specifically wondering about Haskell.

My current thought thought process is that it is possible given that each argument is only referenced once and you are able to rearrange the order in which the function takes in its arguments, meaning you should be able to refactor each argument to the end of the function one by one, but I don't know how to justify this other than a gut feel meaning I am likely wrong. Additionally there are cases where a function with multiple references to is argument(s) can be refactored to be point free, for example myFunc x = 2*x + x*x can become myFunc = uncurry (+) . ((2*) &&& (^2)), so even if my thoughts were correct it wouldn't be all encompassing.

As a disclaimer, I am quite new to Haskell and functional programming.


Solution

  • It’s always possible to write a function in pointfree form. The result may not be very readable if the problem isn’t well suited to pointfree style.

    A generic procedure for doing this is called an abstraction elimination algorithm, which corresponds to a proof that any lambda term can be converted to a pointfree combinator calculus like SKI. Such an algorithm is used by pointfree.io. The automatic translation uses (<*>) (S), const/pure (K), and id (I), as well as other combinators like (.)/fmap (B) and flip (C) to try to make the result more compact. Unfortunately it doesn’t use the dataflow operators from Control.Arrow, but those are very helpful for making a more readable result when writing pointfree code by hand.

    In Haskell you also need to be conscious of the fact that variables have an effect on both evaluation order (pattern matching) and sharing (reusing a variable)—that is, to translate a language feature that depends on variables, you may need to write some more helper combinators to get exactly the same operations.