# Data Types * * * <i> Topics: * let expressions * variants * records * tuples * pattern matching with let and functions </i> * * * ## Let expressions In our use of the word let thus far, we've been making definitions in the toplevel and in .ml files. For example,  # let x = 42;; val x : int = 42  defines x to be 42, after which we can use x in future definitions at the toplevel. We'll call this use of let a *let definition*. There's another use of let which is as an expression:  # let x = 42 in x+1 - : int = 43  Here we're *binding* a value to the name x then using that binding inside another expression, x+1. We'll call this use of let a *let expression*. Since it's an expression it evaluates to a value. That's different than definitions, which themselves do not evaluate to any value. You can see that if you try putting a let definition in place of where an expression is expected:  # (let x = 42) + 1 Error: Syntax error: operator expected.  Syntactically, a let definition is not permitted on the left-hand side of the + operator, because a value is needed there, and definitions do not evaluate to values. On the other hand, a let expression would work fine:  # (let x = 42 in x) + 1 - : int = 43  Another way to understand let definitions at the toplevel is that they are like let expression where we just haven't provided the body expression yet. Implicitly, that body expression is whatever else we type in the future. For example,  # let a = "big";; # let b = "red";; # let c = a^b;; # ...  is understand by OCaml in the same way as  let a = "big" in let b = "red" in let c = a^b in ...  That latter series of let bindings is idiomatically how several variables can be bound inside a given block of code. **Syntax.**  let x = e1 in e2  As usual x is an identifier. We call e1 the *binding expression*, because it's what's being bound to x; and we call e2 the *body expression*, because that's the body of code in which the binding will be in scope. **Dynamic semantics.** To evaluate let x = e1 in e2: * Evaluate e1 to a value v1. * Substitute v1 for x in e2, yielding a new expression e2'. * Evaluate e2' to a value v2. * The result of evaluating the let expression is v2. Here's an example:  let x = 1+4 in x*3 --> (evaluate e1 to a value v1) let x = 5 in x*3 --> (substitute v1 for x in e2, yielding e2') 5*3 --> (evaluate e2' to v2) 15 (result of evaluation is v2)  If you compare these evaluation rules to the rules for function application, you will notice they both involve substitution. This is not an accident. In fact, anywhere let x = e1 in e2 appears in a program, we could replace it with (fun x -> e2) e1. They are syntactically different but semantically equivalent. So let expressions are really syntactic sugar for anonymous function application. **Static semantics.** * If e1:t1 and if under the assumption that x:t1 it holds that e2:t2, then (let x = e1 in e2) : t2. We use the parentheses above just for clarity. As usual, the compiler's type inferencer determines what the type of the variable is, or the programmer could explicitly annotate it with this syntax:  let x : t = e1 in e2  ## Variants A *variant* is a data type representing a value that is one of several possibilities. At their simplest, variants are like enums from C or Java:  type day = Sun | Mon | Tue | Wed | Thu | Fri | Sat let d:day = Tue  The individual names of the values of a variant are called *constructors* in OCaml. In the example above, the constructors are Sun, Mon, etc. This is a somewhat different use of the word constructor than in C++ or Java. For each kind of data type in OCaml, we've been discussing how to build and access it. For variants, building is easy: just write the name of the constructor. For accessing, we use pattern matching. For example:  let int_of_day d = match d with | Sun -> 1 | Mon -> 2 | Tue -> 3 | Wed -> 4 | Thu -> 5 | Fri -> 6 | Sat -> 7  There isn't any kind of automatic way of mapping a constructor name to an int, like you might expect from languages with enums. **Syntax.** Defining a variant type:  type t = C1 | ... | Cn  The constructor names must begin with an uppercase letter. OCaml uses that to distinguish constructors from variable identifiers. The syntax for writing a constructor value is simply its name, e.g., C. **Dynamic semantics.** * A constructor is already a value. There is no computation to perform. **Static semantics.** * if t is a type defined as type t = ... | C | ..., then C : t. Suppose there are two types defined with overlapping constructor names, for example,  type t1 = C | D type t2 = D | E let x = D  When D appears after these definitions, to which type does it refer? That is, what is the type of x above? The answer is that the type defined later wins. So x : t2. That is potentially surprising to programmers, so within any given scope (e.g., a file or a module, though we haven't covered modules yet) it's idiomatic whenever overlapping constructor names might occur to prefix them with some distinguishing character. For example, suppose we're defining types to represent Pok&eacute;mon:  type ptype = TNormal | TFire | TWater type peff = ENormal | ENotVery | ESuper  Because "Normal" would naturally be a constructor name for both the type of a Pok&eacute;mon and the effectiveness of a Pok&eacute;mon attack, we add an extra character in front of each constructor name to indicate whether it's a type or an effectiveness. **Pattern matching.** As we said in the last lecture, each time we introduced a new kind of data type, we need to introduce the new patterns associated with it. For variants, this is easy. We add the following new pattern form to the list of legal patterns: * a constructor name C And we extend the definition of when a pattern matches a value and produces a binding as follows: * The pattern C matches the value C and produces no bindings. **Note.** Variants are actually considerably more powerful than what we have seen today. We'll return to them again in a future lecture. ## Records A *record* is a kind of type in OCaml that programmers can define. It is a composite of other types of data, each of which is named. OCaml records are much like structs in C. Here's an example of a record type definition for a Pok&eacute;<u>mon</u>:  type mon = {name: string; hp : int; ptype: ptype}  This type defines a record with three *fields* named name, hp (hit points), and ptype (defined above). The type of each of those fields is also given. Note that ptype can be used as both a type name and a field name; the *namespace* for those is distinct in OCaml. To build a value of a record type, we write a record expression, which looks like this:  {name = "Charmander"; hp = 39; ptype = TFire}  So in a type definition we write a colon between the name and the type of a field, but in an expression we write an equals sign. To access a record and get a field from it, we use the dot notation that you would expect from many other languages. For example:  # let c = {name = "Charmander"; hp = 39; ptype = TFire};; # c.hp;; - : int = 39  It's also possible to use pattern matching to access record fields:  match c with | {name=n; hp=h; ptype=t} -> h  The n, h, and t here are pattern variables. There is a syntactic sugar provided if you want to use the same name for both the field and a pattern variable:  match c with | {name; hp; ptype} -> hp  Here, the pattern {name; hp; ptype} is sugar for {name=name; hp=hp; ptype=ptype}. In each of those subexpressions, the identifier appearing on the left-hand side of the equals is a field name, and the identifier appearing on the right-hand side is a pattern variable. **Syntax.** A record expression is written:  {f1 = e1; ...; fn = en}  The order of the fi=ei inside a record expression is irrelevant. For example, {f=e1;g=e2} is entirely equivalent to {g=e2;f=e1}. A field access is written:  e.f  where f is an identifier of a field name, not an expression. **Dynamic semantics.** * If for all i in 1..n, it holds that ei ==> vi, then {f1=e1; ...; fn=en} ==> {f1=v1; ...; fn=vn}. * If e ==> {...; f=v; ...} then e.f ==> v. **Static semantics.** A record type is written:  {f1 : t1; ...; fn : tn}  The order of the fi:ti inside a record type is irrelevant. For example, {f:t1;g:t2} is entirely equivalent to {g:t2;f:t1}. Note that record types must be defined before they can be used. This enables OCaml to do better type inference than would be possible if record types could be used without definition. The type checking rules are: * If for all i in 1..n, it holds that ei : ti, and if t is defined to be {f1:t1; ...; fn:tn}, then {f1=e1; ...; fn=en} : t. Note that the set of fields provided in a record expression must be the full set of fields defined as part of the record's type. * If e : t1 and if t1 is defined to be {...; f:t2; ...}, then e.f : t2. **Record copy.** Another syntax is also provided to construct a new record out of an old record:  {e with f1 = e1; ...; fn = en}  This doesn't mutate the old record; it constructs a new one with new values. The set of fields provided after the with does not have to be the full set of fields defined as part of the record's type. In the newly copied record, any field not provided as part of the with is copied from the old record. The dynamic and static semantics of this are what you might expect, though they are tedious to write down mathematically. **Pattern matching.** We add the following new pattern form to the list of legal patterns: * {f1=p1; ...; fn=pn} And we extend the definition of when a pattern matches a value and produces a binding as follows: * If for all i in 1..n, it holds that pi matches vi and produces bindings \$$b_i\$$, then the record pattern {f1=p1; ...; fn=pn} matches the record value {f1=v1; ...; fn=vn; ...} and produces the set \$$\bigcup_i b_i\$$ of bindings. Note that the record value may have more fields than the record pattern does. As a syntactic sugar, another form of record pattern is provided: {f1; ...; fn}. It is desugared to {f1=f1; ...; fn=fn}. ## Tuples A *tuple* is another kind of type in OCaml that programmers can define. Like records, it is a composite of other types of data. But instead of naming the *components*, they are identified by position. Here are some examples of tuples:  (1,2,10) 1,2,10 (true, "Hello") ([1;2;3], (0.5,'X'))  A tuple with two components is called a *pair*. A tuple with three components is called a *triple*. Beyond that, we usually just use the word *tuple* instead of continuing a naming scheme based on numbers. Also, beyond that, it's arguably better to use records instead of tuples, because it becomes hard for a programmer to remember which component was supposed to represent what information. Building of tuples is easy: just write the tuple, as above. Accessing again involves pattern matching, for example:  match (1,2,3) with | (x,y,z) -> x+y+z  **Syntax.** A tuple is written  (e1, e2, ..., en)  The parentheses are optional but might sometimes be necessary to ensure the compiler parses your code the way you intended. One place where it is somewhat idiomatic to omit them is in a match expression between the match and with keywords (and also in the patterns in the following branches). **Dynamic semantics.** * if for all i in 1..n it holds that ei ==> vi, then (e1, ..., en) ==> (v1, ..., vn). **Static semantics.** Tuple types are written using a new type constructor *, which is different than the multiplication operator. The type t1 * ... * tn is the type of tuples whose first component has type t1, ..., and nth component has type tn. * if for all i in 1..n it holds that ei : ti, then (e1, ..., en) : t1 * ... * tn. **Pattern matching.** We add the following new pattern form to the list of legal patterns: * (p1, ..., pn) The parentheses are optional but might sometimes be necessary to ensure the compiler parses your code the way you intended. And we extend the definition of when a pattern matches a value and produces a binding as follows: * If for all i in 1..n, it holds that pi matches vi and produces bindings \$$b_i\$$, then the tuple pattern (p1, ..., pn) matches the tuple value (v1, ..., vn) and produces the set \$$\bigcup_i b_i\$$ of bindings. Note that the tuple value must have exactly the same number of components as the tuple pattern does. ## One-of vs. each-of The big difference between variants and tuples/records is that a value of a variant type is *one of* a set of possibilities, whereas a value of a tuple/record type provides *each of* a set of possibilities. Going back to our examples, a value of type day is **one of** Sun or Mon or etc. But a value of type mon provides **each of** a string and an int and ptype. Note how, in those previous two sentences, the word "or" is associated with variant types, and the word "and" is associated with tuple/record types. That's a good clue if you're ever trying to decide whether you want to use a variant or a tuple/record: if you need one piece of data *or* another, you want a variant; if you need one piece of data *and* another, you want a tuple/record. One-of types are more commonly known as *sum types*, and each-of types as *product types*. Those names come from set theory. Variants are like [disjoint union][disjun], because each value of a variant comes from one of many underlying sets (and thus far each of those sets is just a single constructor hence has cardinality one). And disjoint union is is sometimes written with a summation operator \$$\Sigma\$$. Tuples/records are like [Cartesian product][cartprod], because each value of a tuple/record contains a value from each of many underlying sets. And Cartesian product is usually written with a product operator \$$\times\$$. [disjun]: https://en.wikipedia.org/wiki/Disjoint_union [cartprod]: https://en.wikipedia.org/wiki/Cartesian_product ## Let and pattern matching The syntax we've been using so far for let expressions is, in fact, a special case of the full syntax that OCaml permits. That syntax is:  let p = e1 in e2  That is, the left-hand side of the binding may in fact be a pattern, not just an identifier. Of course, variable identifiers are on our list of valid patterns, so that's why the syntax we've studied so far is just a special case. Given this syntax, we revisit the semantics of let expressions. **Dynamic semantics.** To evaluate let p = e1 in e2: 1. Evaluate e1 to a value v1. 2. Match v1 against pattern p. If it doesn't match, raise the exception Match_failure. Otherwise, if it does match, it produces a set \$$b\$$ of bindings. 3. Substitute those bindings \$$b\$$ in e2, yielding a new expression e2'. 4. Evaluate e2' to a value v2. 5. The result of evaluating the let expression is v2. **Static semantics.** * If all the following hold: - e1:t1 - the pattern variables in p are x1..xn - e2:t2 under the assumption that for all i in 1..n it holds that xi:ti, then (let p = e1 in e2) : t2. **Let definitions.** As before, let definitions can be understood as let expression whose body has not yet been given. So their syntax can be generalized to  let p = e  and their semantics follow from the semantics of let expressions, as before. ## Functions and pattern matching The syntax we've been using so far for functions is also a special case of the full syntax that OCaml permits. That syntax is:  let f p1 ... pn = e1 in e2 (* function as part of let expression *) let f p1 ... pn = e (* function definition at toplevel *) fun p1 ... pn -> e (* anonymous function *)  The truly primitive syntactic form we need to care about is fun p -> e. Let's revisit the semantics of anonymous functions and their application with that form; the changes to the other forms follow from those below: **Static semantics.** * Let x1..xn be the pattern variables appearing in p. If by assuming that x1:t1 and x2:t2 and ... and xn:tn, we can conclude that p:t and e:u, then fun p -> e : t -> u. * The type checking rule for application is unchanged. **Dynamic semantics.** * The evaluation rule for anonymous functions is unchanged. * To evaluate e0 e1: 1. Evaluate e0 to an anonymous function fun p -> e. 2. Evaluate e1 to value v1. 3. Match v1 against pattern p. If it doesn't match, raise the exception Match_failure. Otherwise, if it does match, it produces a set \$$b\$$ of bindings. 4. Substitute those bindings \$$b\$$ in e, yielding a new expression e'. 5. Evaluate e' to a value v, which is the result of evaluating e0 e1. ## Using patterns Here are many examples of how to use patterns with the various language features we've seen today:  (* Pokemon types *) type ptype = TNormal | TFire | TWater (* A record to represent Pokemon *) type mon = {name: string; hp : int; ptype: ptype} (********************************************* * Several ways to get a Pokemon's hit points: *********************************************) (* OK *) let get_hp m = match m with | {name=n; hp=h; ptype=t} -> h (* better *) let get_hp m = match m with | {name=_; hp=h; ptype=_} -> h (* better *) let get_hp m = match t with | {name; hp; ptype} -> hp (* better *) let get_hp m = match m with | {hp} -> hp (* best *) let get_hp m = m.hp (************************************************** * Several ways to get the 3rd component of a tuple **************************************************) (* OK *) let thrd t = match t with | (x,y,z) -> z (* good *) let thrd t = let (x,y,z) = t in z (* better *) let thrd t = let (_,_,z) = t in z (* best *) let thrd (_,_,z) = z (************************************* * How to get the components of a pair *************************************) let fst (x,_) = x let snd (_,y) = y (* both fst and snd are functions already provided in the standard library *)  ## Additional patterns Here are some addition pattern forms that are useful: * p1 | ... | pn: an "or" pattern; matching against it succeeds if a match succeeds against any of the individual patterns pi, which are tried in order from left to right. All the patterns must bind the same variables. * (p : t): a pattern with an explicit type annotation. * c: here, c means any constant, such as integer literals, string literals, and booleans. * 'ch1'..'ch2': here, ch means a character literal. For example, 'A'..'Z' matches any uppercase letter. You can read about [all the pattern forms][patterns] in the manual. [patterns]: http://caml.inria.fr/pub/docs/manual-ocaml/patterns.html ## Summary Let expressions can be used to provide local scope for variables: the binding is in scope only in the body of the let expression. OCaml provides data types for variants (one-of types) and tuples and products (each-of types). Pattern matching can be used to access values of each of those data types. And pattern matching can be used in let expressions and functions. ## Terms and concepts * binding * binding expression * body expression * constructor * each-of type * field * let definition * let expression * one-of type * pair * product type * record * substitution * sum type * triple * tuple * variant ## Further reading * *Introduction to Objective Caml*, chapters 3, 5.2, 8.1 * *OCaml from the Very Beginning*, chapters 2, 5, 8 * *Real World OCaml*, chapters 2, 5