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); orelt :: 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