Point-free programming style in F#

I gave a short presentation at Functional programming Stockholm user group about point-free programming style in F# which I will write a summary of here.

I was reading Tomas Petricek’s and Jon Skeet’s book Real-World Functional Programming which contains a short section about point-free style. The conclusion was that the code could end up being hard to read. However, I found the examples in the book quite elegant and was intrigued to learn more.

Point-free style originates from a mathematical branch called topology which deals with spaces composed by points (values) and functions between those spaces. A function is said to be point-free if it doesn’t mention the points of the space which it operates on. In functional programming this translates to a function that doesn’t mention the arguments of its transform. The point (no pun…) is to make the code less verbose and to focus more on behavior of the function than on its data.

In order to accomplish point-free style, functional programming features such as higher-order functions, function composition and partial function application are used. Let’s look at some examples:

let rec sum list =
   match list with
   | [] -> 0;
   | h::t -> h + sum t

This function sums the elements of a list recursively. Since the arguments are bound in a pattern matching expression they can’t be taken out so we need to rewrite it using a higher order function like so:

let sum list = List.fold (+) 0 list

The fold function takes an aggregating function, a seed value and a list as arguments (note that the +-operator is surrounded by parentheses which turns it into a function). The function’s type signature is:

val sum : int list -> int

That is, it’s a function taking a list of integers and returning an integer value.
Now, if we remove the list argument we get:

let sum = List.fold (+) 0

and the type signature:

val sum : (int list -> int)

The signature is the same but surrounded by parentheses which means that the sum function returns a function instead of a value, i.e. it’s a partial function application. Since the signature is the same as previously the usage is the same e.g.

let addingNumbersOneToTen = sum [1..10]

Here’s another example:

let add10To list = List.map(fun x -> x + 10) list

The map function applies the given function to each element of the passed list. In this case, a lambda function is used for adding 10 to each element. Using a partial function application instead of the lambda we get:

let add10To list = List.map((+) 10) list

and without the list argument:

let add10To = List.map((+) 10)

which is completely point-free.

Finally an example of using function composition to obtain point-freedom:

let doubleAndIncr = fun x -> x * 2 + 1

This function, as the name implies, doubles the given value and increments it with one.
Composing the multiply function and the add function will get rid of the lambda function:

let doubleAndIncr x = ((*) 2 >> (+) 1) x

and making it a partial function application will loose the x argument:

let doubleAndIncr = (*) 2 >> (+) 1

I think point-free style can make the code more readable when used wisely. As in the last example above the expression to the right reads almost like natural language “times 2 and then plus 1”. Of course, it could get really gory but so can anything else in the world of programming.

Tacit programming
Point-free style: What is it good for?

Leave a Reply

Close Menu