Language of Booleans
BNF for Booleans
t ::= True | False | if t1 then t2 else t3
v ::= True | False
• t stands for the terms of the language
• v stands for the values of the language
• Values are subsets of terms – we will try to
maintain this subset relationship in all
languages we study.
• The language of Booleans is the “object
language” or the “defined language”. This is
the language we will write an interpreter for.
• The interpreter will be written in another
language; this language is called the
“metalanguage” or the “defining language”.
• For this course the metalanguage will
always be OCaml.
• We want to represent the terms of
Booleans in OCaml. How to do that?
• The answer to the question is the same as
the answer to: “How to represent different
geometric shapes as values of a type”?
• Hence we must declare a new type, terms, and
tag the different terms with different constructors.
That is: Use “sum-of-product types”.
Representing terms (contd.)
type figure = Circ of int | Rect of int * int | Tri of int * int * int
type ’a bintree = Leaf | Node of ’a bintree * ’a * ’a bintree
type term = True | False | Cnd of term * term * term
The Cnd tag is for the if-then-else or “conditional”
The interpreter: type
• The interpreter, eval, has type
term -> term
• That is, eval takes a term as input and
grinds out a value as output, if the
• We said: values are subsets of terms. So it
makes sense for eval to have the above
The interpreter: code
let rec eval = fun
True -> True
| False -> False
| Cnd(t1, t2, t3) -> match (eval t1) with
True -> eval t2
| False -> eval t3
| _ -> raise NoEvaluationPossible
Notes on interpreter code
• Instead of let rec eval = function …we could
have written: let rec eval t = match t with …
• A term can be thought of as a tree with True and
False labelling its leaves and Cnd labelling its internal
• Interpreting a term is like processing a tree: find
results of subtrees and “glue” the results.
• Example: to process Cnd, find result of subtree
t1, and depending on the result, process subtree t2
• Note how the meaning of Cnd (in object language) is
defined in terms of match (or if-then-else) in OCaml.
let s = if True then False else False;;
let t = if s then True else True;;
let u = if False then True else True;;
Then: eval Cnd(t, False, True) = let b = eval t in …
Note that: eval s = False so that eval t = True
Thus eval Cnd(t, False, True)
= let b = True in
match b with
True -> eval False
This yields the final value of False.
• eval computes the final value of an input term.
• What if we wanted to observe intermediate results of the
• For the example on slide 9 we would like:
if t then False else True
-> if (if False then True else True) then False else True
because in one step:
t = if s then True else False -> if False then True else True
And this is because in one step:
s = if True then False else False -> False
If we want to further evaluate if (if False then True else True) then False else True,
we get if True then False else True in one step and then False in a further step.
The notation t1 -> t2 should be read: t1 goes to t2 in one step.
• You can also think of -> as describing transitions in an abstract
machine: A state of the machine is a term of the language. The
machine “goes to” the next state via the transition function, ->.
(0) if True then t1 else t2 -> t1
(1) if False then t1 else t2 -> t2
t1 -> t1’
if t1 then t2 else t3 -> if t1’ then t2 else t3
• Rule (0) says: if True then t1 else t2 goes to t1 in one evaluation
• Rule (1) says: if False then t1 else t2 goes to t2 in one evaluation
• Rule (2) says: provided t1 goes to t1’ in one evaluation step, then :
if t1 then t2 else t3 goes to if t1’ then t2 else t3 in one evaluation step.
• Recall the inference-rule notation in Rule (2) from the Tegrity
lectures on “A Quick Tour of OCaml”.
• Note how the rules enforce the “evaluation is left-to-right and by
value” principle of evaluation.
• Note that there are no rules of the form: True -> True or
False -> False; this is because the rules describe one-step evaluation.
Values are “atomic”: they evaluate to themselves in zero steps.
The one-step interpreter code
let rec eval1 = fun
Cnd(True, t2, t3) -> t2
| Cnd(False, t2, t3) -> t3
| Cnd(t1, t2, t3) ->
let t1’ = eval1 t1 in Cnd(t1’, t2, t3)
| _ -> raise NoEvaluationPossible;;
Notes on eval1
• The ordering of the cases in the match
• The _ is a “wild-card pattern”: it matches
all terms other than the ones described in
• Because there are no rules for True and
False, the _ raises an exception.