I've recently started learning F# and come across curried functions for simple examples such as the following:
Consider a function that calculates sales by multiplying price p
by number of units sold n
.
let sales (p,n) = p * (float n);;
The type of this function is given as
val sales : p:float * n:int -> float
i.e. take a pair of float
and int
and returns a float
.
We can instead write this as a curried function
let salesHi p n = p * (float n);;
The type of this function is given as
val salesHi : p:float -> n:int -> float
i.e. takes a float
and returns a function of int
to float
.
In simple cases this seems to make no difference
sales (0.99, 100);;
salesHi 0.99 100;;
Both give
val it : float = 99.0
However with the curried function I can feed in the price for particular items to get new functions. E.g.
let salesBeer = salesHi 5.99;;
let salesWine = salesHi 14.99;;
Then salesBeer 2
gives 11.98
and salesWine 2
gives 29.98
.
Also, I've noticed that built-in operators such as +
are defined as functions, so I can write, for example:
let plus2 = (+) 2;
List.map plus2 [1;3;-1];;
and get
val it : int list = [3; 5; 1]
This seems like a good thing. So when I want to implement a function in an imperative language that would have taken n > 1
arguments, should I for example always use a curried function in F# (so long as the arguments are independent)? Or should I take the simple route and use regular function with an n
-tuple and curry later on if necessary? Or something else?
How do F# programmers decide when to make a function in curried form or use a regular function with a tuple?