Recitation 2: Tuples, records and datatypes
Tuples
Every function in OCaml takes exactly one value and returns exactly one result. For instance, our
squareRoot
function takes one float value and returns one float value. The advantage of always taking
one argument and returning one result is that the language is extremely uniform. Later, we'll see that this
buys us a lot when it comes to
composing
new functions out of old ones.
But it looks like we can write functions that take more than one argument! For instance, we may write:
let max1(r1, r2):float =
if r1 < r2 then r2
else r1
max1(3.1415, 2.718)
and it appears as if max1 takes two arguments. In truth max1 takes one argument that is a
2tuple
(also
known as an ordered pair.)
In general, an
ntuple
is an ordered sequence of
n
values written in parenthesis and separated by commas as
(
expr, expr,
...,
expr
). For instance,
(42, "hello", true)
is a 3tuple that contains the integer
42
as
its first component, the string
"hello"
as its second component, and the boolean value
true
as its third
component. As another example,
()
is the empty tuple. This is called "unit" in OCaml.
When you call a function in OCaml, if it takes more than one argument, then you have to pass it a tuple of the
arguments. For instance, when we write:
max1(3.1415, 2.718)
we're passing the 2tuple
(3.1415, 2.718)
to the function max1. We could just as well write:
val args = (3.1415, 2.178);
max1 args
(* evaluates to 3.1415 *)
The type of an ntuple is written
(
t
1
*
...
*
t
n
)
. For instance, the type of args above is
(float*float)
.
This notation is based on the Cartesian product in mathematics (i.e., the plane is R^2 = R * R).
Similarly, the 3tuple
(42, "hello", true)
has type
(int * string * bool)
. Notice that
max1
has type
(float*float)>float
, indicating that it takes one argument (a 2tuple of floats) and
returns one result (a float).
Combining what we've seen so far, we can write a grammar for the basic types as follows:
t
::=
int

float

bool

string

char

t
1
*
...
*
t
n

t
1
>
t
2

(
t
)
There are a few tricky parts to this. The two most important are that
>
has lower precedence than
*
, so the
types
(float*float)>float
and
float*float>float
are exactly the same type. The second is