If Expressions
The expression if e1 then e2 else e3
evaluates to e2
if e1
evaluates to
true
, and to e3
otherwise. We call e1
the guard of the if
expression.
# if 3 + 5 > 2 then "yay!" else "boo!";;
- : string = "yay!"
Unlike if-then-else
statements that you may have used in imperative
languages, if-then-else
expressions in OCaml are just like any other
expression; they can be put anywhere an expression can go. That makes them
similar to the ternary operator ? :
that you might have used in other
languages.
# 4 + (if 'a' = 'b' then 1 else 2);;
- : int = 6
If
expressions can be nested in a pleasant way:
if e1 then e2
else if e3 then e4
else if e5 then e6
...
else en
You should regard the final else
as mandatory, regardless of whether you are
writing a single if
expression or a highly nested if
expression. If you
omit it you'll likely get an error message that, for now, is inscrutable:
# if 2>3 then 5;;
Error: This expression has type int but an expression was expected of type unit
Syntax. The syntax of an if
expression:
if e1 then e2 else e3
The letter e
is used here to represent any other OCaml expression; it's an
example of a syntactic variable aka metavariable, which is not actually
a variable in the OCaml language itself, but instead a name for a certain
syntactic construct. The numbers after the letter e
are being used
to distinguish the three different occurrences of it.
Dynamic semantics.
The dynamic semantics of an if
expression:
if
e1
evaluates totrue
, and ife2
evaluates to a valuev
, thenif e1 then e2 else e3
evaluates tov
if
e1
evaluates tofalse
, and ife3
evaluates to a valuev
, thenif e1 then e2 else e3
evaluates tov
.
We call these evaluation rules: they define how to evaluate expressions. Note
how it takes two rules to describe the evaluation of an if
expression, one for
when the guard is true, and one for when the guard is false. The letter v
is
used here to represent any OCaml value; it's another example of a metavariable.
Later we will develop a more mathematical way of expressing dynamic semantics,
but for now we'll stick with this more informal style of explanation.
Static semantics. The static semantics of an if
expression:
- if
e1
has typebool
ande2
has typet
ande3
has typet
thenif e1 then e2 else e3
has typet
We call this a typing rule: it describes how to type check an expression. Note
how it only takes one rule to describe the type checking of an if
expression.
At compile time, when type checking is done, it makes no difference whether the
guard is true or false; in fact, there's no way for the compiler to know what
value the guard will have at run time. The letter t
here is used to represent
any OCaml type; the OCaml manual also has definition of all types
(which curiously does not name the base types of the language like int
and
bool
).
We're going to be writing "has type" a lot, so let's introduce a more compact
notation for it. Whenever we would write "e
has type t
", let's instead
write e : t
. The colon is pronounced "has type". This usage of colon
is consistent with how the toplevel responds after it evaluates an expression
that you enter:
# let x = 42;;
val x : int = 42
In the above example, variable x
has type int
, which is what the colon
indicates.