Currying is a transformation process which converts a function with multiple arguments into a chain of embedded functions, each with single parameter. In F# function declarations are curried by default. Therefore you don’t usually need to curry functions. But even if this is an automatic transformation process it is helpful to understand why functions are used in this way.
The following example shows functions to sum two values. The first function has two parameters and the second function has only one parameter, a tuple with the needed values.
//create functions let sum1(x,y) = x+y let sum2 x y = x+y //use functions let x = sum1(2,3) let y = sum2 2 3 let values = (2,3) let z = sum1 values
Except of the syntax there are no visible differences between these two functions. Therefore we want to take a deeper look into the curried functions. Let’s start by looking at the function declaration:
val sum1 : int * int -> int
val sum2 : int -> int -> int
The first function takes a tuple and returns an integer. The second function instead gets an integer and returns a function which gets an integer and returns an integer. Therefore the function sum2, with the two parameters is transformed by default into a chain of single-parameter functions.
The following source code shows this sum function again and the resulting curried version of the function. In line 11 you see that it is possible to call the function with a single parameters and use the returning function to call it with the second parameter.
let sum x y = x+y let sum_curried = fun x -> fun y -> x+y let x = sum 2 3 let y = sum_curried 2 3 let z = (sum 2) 3
Partial application of arguments
Curried functions offer an easy way to create partial functions. I want to demonstrate this with the next example. Let’s say we want to implement a function which increases the given parameter by adding 3. Of course for this issue we may use our already implemented sum function. We know that the curried version of this function is called with one parameter and will return another function which needs the second parameter as input. Therefore it is possible to create the add function by using the sum function with parameter 3. The following source code shows an according example.
let sum x y = x+y let add3 = sum 3 let x = add3 2
Partial application of arguments can be done for functions that take tupled arguments as well. But in this case an explicit lambda function is needed. The following example shows the implementation needed for the tupled function.
let sum(x,y) = x+y let add3 = fun x -> sum(x,3) let x = add3 2
Pipe operator and partial applications
At next I want to show you another example which uses curried functions. Within the next use case we want to implement a function which doubles up all values of a list. The following source code shows a possible implementation. The function double was created which doubles up a value. Furthermore the function doubleAll is implemented which maps the double function with the list values.
let double x = 2*x let doubleAll values = List.map double values let originList = [1;2;3] let newList = doubleAll originList
However I don’t like the doubleAll function because it does not add much value and only calls another function. Therefore it is also possible to implement the same solution by using List.map without the unnecessary doubleAll function. The following source code shows possible implementations.
let double x = 2*x let originList = [1;2;3] let newListA = List.map double originList let newListB = (List.map double) originList let newListC = originList |> List.map double
As you can see I have implemented three different ways to use the List.map function. This is possible because this function is curried. In general, partial application of curried functions is a useful technique. In practice I really like the possibility to call curried functions by using the pipe operator. If you compare the three implementations in the example above you will see that the third version which uses the pipe operator is the one which is most easy to read and understand.
In general, when programming in F#, you should prefer the curried format of functions. This will avoid needless parentheses and allow you to easily create partial application. Currying in combination with the pipe operator allow you to create very nice and clean source code.