12 CHAPTER 2. A TASTE OF CAML
#fun x -> (fun y -> x + y);;
it : int -> int -> int = <fun>
#(fun x -> (fun y -> x + y)) 1;;
it : int -> int = <fun>
#((fun x -> (fun y -> x + y)) 1) 2;;
it : int = 3
Note that the function has type int -> int -> int, meaning int -> (int ->
int). When applied to one argument, 1, it yields another function, which takes the
second argument and maps it to the corresponding sum. Currying is used a lot in
functional programming, since it allows functions to be used quite flexibly. Some
other syntactic conventions support it; for example, without parentheses to enforce
grouping, function application associates to the left, i.e. f g x means (f g)(x) not
f(g(x)). We can write the above example more succinctly as:
#(fun x y -> x + y) 1 2;;
it : int = 3
2.3 Bindings and declarations
A nontrivial functional program is a very complex expression, and it is of course
not convenient to evaluate it all in one go. Instead, useful subexpressions can be
evaluated and bound to names using let. (In fact, a filter in front of CAML Light,
part of HOL Light, automatically binds the last anonymous expression evaluated
to the special name it, hence its appearance above.) For example:
#let successor = fun x -> x + 1;;
successor : int -> int = <fun>
#successor 5;;
it : int = 6
Declarations can be made local to the evaluation of an expression, so they are
invisible afterwards, using in. For example:
#let suc = fun x -> x + 1 in
suc(suc 1);;
it : int = 3
#suc 1;;
Toplevel input:
>let it = suc 1;;
> ^^^
The value identifier suc is unbound.
The arguments to functions can be written on the left of the equation, which
most people find more natural:
#let successor x = x + 1;;
successor : int -> int = <fun>
#successor 5;;
it : int = 6
Functions can be recursive, i.e. defined in terms of themselves. To achieve this,
simply include the keyword rec. For example, the factorial n! = 1×2×· · ·×(n−1)×n
can be evaluated as follows: evaluate (n − 1)! recursively, then multiply by n: