In F#, all functions take exactly one parameter. This seems an odd statement, since it's trivially easy to declare more than one parameter in a function declaration:
let add x y = x + y
But if you type that function declaration into the F# interactive interpreter, you'll see that its type signature is:
val add : x:int -> y:int -> int
Without the parameter names, that signature is int -> int -> int
. The ->
operator is right-associative, which means that this signature is equivalent to int -> (int -> int)
. In other words, add
is a function that takes one int
parameter, and returns a function that takes one int
and returns int
. Try it:
let addTwo = add 2
// val addTwo : (int -> int)
let five = addTwo 3
// val five : int = 5
However, you can also call a function like add
in a more "conventional" manner, directly passing it two parameters, and it will work like you'd expect:
let three = add 1 2
// val three : int = 3
This applies to functions with as many parameters as you want:
let addFiveNumbers a b c d e = a + b + c + d + e
// val addFiveNumbers : a:int -> b:int -> c:int -> d:int -> e:int -> int
let addFourNumbers = addFiveNumbers 0
// val addFourNumbers : (int -> int -> int -> int -> int)
let addThreeNumbers = addFourNumbers 0
// val addThreeNumbers : (int -> int -> int -> int)
let addTwoNumbers = addThreeNumbers 0
// val addTwoNumbers : (int -> int -> int)
let six = addThreeNumbers 1 2 3 // This will calculate 0 + 0 + 1 + 2 + 3
// val six : int = 6
This method of thinking about multi-parameter functions as being functions that take one parameter and return new functions (which may in turn take one parameter and return new functions, until you reach the final function that takes the final parameter and finally returns a result) is called currying, in honor of mathematician Haskell Curry, who is famous for developing the concept. (It was invented by someone else, but Curry deservedly gets most of the credit for it.)
This concept is used throughout F#, and you'll want to be familiar with it.