Making sense of an auto curried language

Thursday, July 7, 2016

Partial Application and Currying are two common confusion points for people coming to autocurried languages for the first time. Often they'll say things like "this function takes 2 ints and returns an int". The reality is actually much simpler than that, though it may be a different way of thinking about the problem.

In an autocurried language every function takes one thing and returns one thing

In the following function it's obvious that we accept an int and return an int. In fact if we look at the signature for the function we see that it is int -> int.

let add1 x = x + 1

But what about functions like add that "take two arguments"?

let add x y = x + y

The fact that you can provide "two arguments" to a function is just syntactic sugar. What we've really done with that function is said that we have a function named add that when given an int will return a function that takes an int and returns an int. That's what those arrows are all about in the function signature int -> int -> int.

We could write out the equivalent concept in C# if we manually curried the function.

Func<int, Func<int,int>> add = x => y => x + y;
var three = add(2)(1);

Of course in C# this looks odd because of the parens surrounding each argument, but that's actually the same thing we're doing with the F# code. In F#, Haskell, and other ML dialect languages function application happens by the use of a space. foo bar means apply the argument bar to the function foo, while the ALGOL family of languages uses parenthesis foo(bar).

Currying is the process of breaking a multi argument function into a function that takes an argument and returns a value, Partial Application is what happens when you apply a value to a function and the result of that application is another function.