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 leave it off 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 in the semester 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 write "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.