A program is a sequence of **expressions** that are **evaluated** in order.

Every expression has a unique *value* and *type*.

We’ve seen primitive types and operators, `let (rec)`

expressions, function values and types, and product types (tuples).

Ocaml has a *language* for specifying types: `->`

, `*`

, `'a`

.

Structured data can be accessed through pattern matching.

**Lists** are structured data, whose structure is defined inductively; a list is either:

`[]`

(empty); or`elt :: lst`

(cons)

List “literals:”

Append operator: `l1 @ l2`

(so `[1;2] @ [3;4] ≡ [1;2;3;4]`

)

What about `[1; "one"; '1']`

?

The type of `[] : 'a list`

is a **type constructor**: for any type `τ`

it constructs a new type `τ list`

.

What is the type of `[[1; 2; 3]; [4; 5]]`

?

`'a list`

is another example of a **polymorphic type**.

What about `[[]; 3]`

?

`'a`

can only match one type “at a time:” once we decide `'a = 'b list`

it cannot also match ‘int’.

Pattern matching on lists uses the `[]`

and `::`

constructors:

`match [1;3] with h::t -> h`

`≡ 1`

`match [1;3] with h::t -> t`

`≡ [3]`

`match [3] with h::t -> t`

`≡ []`

`let is_empty = function [] -> true | _::_ -> false`

The inductive definition of lists makes recursion a “good fit:”

Evaluating `sum_int [3;17;42]`

:

`sum_int 3::(17::42::[])`

`≡ 3 + (sum_int 17::(42::[]))`

`≡ 3 + (17 + (sum_int 42::[]))`

`≡ 3 + (17 + (42 + (sum_int [])))`

`≡ 3 + 17 + 42 + 0 ≡ 62`

`let rec length: 'a list -> int =`

`let rec append : 'a list -> 'a list -> 'a list`

`let rec drop : int -> 'a list -> 'a list`

Another example: `reverse : 'a list -> 'a list`

What if we evaluate `reverse [1; 2; …; 𝓃]`

?

`reverse [2;3; …; 𝓃] @[1]`

`reverse [3; …; 𝓃] @[2]`

`⋮`

`reverse [] @[𝓃]`

`[𝓃; …; 3; 2] @ [1]`

`[𝓃; …; 3] @ [2]`

`⋮`

`[] @ [𝓃]`

`cs2041.org`