Monday, April 26, 2010

Currying vs Partial Function Application

There’s a lot of confusion over these two terms. By myself included. But I’m pretty happy now that I understand the difference and wanted to share my newfound knowledge with you, dear reader.

First let’s understand the arrow (->), it’ll make the discussion much easier. This operator (->) is used in F#, Haskell and other functional programming languages to define function types. If you’ve got an ‘add’ function that takes two int arguments and returns an int, you would write that function’s type like this (in F#):

int * int –> int

Which says, the function takes a tuple of two int values and returns an int. Remember F# functions only ever have one argument and one return value. Now take a look at this type:

int –> int –> int

This function takes an int value and returns a function. The function it returns takes an int value and returns an int value. Turning the first example into the second example is ‘currying’. So currying is the process of taking a function with multiple arguments and turning it into a function that takes only one argument and returns a new function that takes the second argument and returns a value (or a further function which takes the third argument and returns a value or…. you get the picture).

Partial application is when you actually use a such a curried function. So in our add example above, if we have defined a curried add (in F#) as:

> let add a b = a + b;;

val add : int -> int -> int

Isn’t that neat, we don’t actually need to ‘curry’ add, F# provides curried functions by default. Now we use the add function like this:

> let add5 = add 5;;

val add5 : (int -> int)

F# is now telling us that add5 is a function that takes an int and returns an int. We’ve partially applied add. Now we can use add5 like any other function:

> add5 2;;
val it : int = 7
> add5 7;;
val it : int = 12

Having curried functions by default is very cool indeed. It means we can use partial application to compose functions in the same way that we use dependency injection to compose classes in object-oriented languages.

No comments: