2.3. BINDINGS AND DECLARATIONS 13
#let rec fact n = if n = 0 then 1
else n * fact(n - 1);;
fact : int -> int = <fun>
#fact 6;;
it : int = 720
By using and, one can make several binding simultaneously, and define mutually
recursive functions. For example, here are two simple, though highly inefficient,
functions to decide whether or not a natural number is odd or even:
#let rec even n = if n = 0 then true else odd (n - 1)
and odd n = if n = 0 then false else even (n - 1);;
even : int -> bool = <fun>
odd : int -> bool = <fun>
#even 12;;
it : bool = true
#odd 14;;
it : bool = false
If declarations do not include the rec keyword, then any instance of the name
currently being bound on the right is taken to be the previous value. For example:
#let successor n = successor(successor n);;
successor : int -> int = <fun>
#successor 2;;
it : int = 4
#successor 5;;
it : int = 7
The old binding is now overwritten. But note that we are not making assign-
ments to variables. Each binding is only done once when the system analyses the
input; it cannot be repeated or modified. It can be overwritten by a new defini-
tion using the same name, but this is not assignment in the usual sense, since the
sequence of events is only connected with the compilation process, not with the
dynamics of program execution. Indeed, apart from the more interactive feedback
from the system, we could equally replace all the double semicolons after the dec-
larations by in and evaluate everything at once. On this view we can see that the
overwriting of a declaration really corresponds to the definition of a new local vari-
able that hides the outer one, according to the scoping rules usual in programming
languages. For example:
#let x = 1;;
x : int = 1
#let y = 2;;
y : int = 2
#let x = 3;;
x : int = 3
#x + y;;
- : int = 5
is the same as:
#let x = 1 in
let y = 2 in
let x = 3 in
x + y;;
- : int = 5