CSE 341 : Programming Languages� �Lecture 6
Nested Patterns, Exceptions
James Wilcox
Winter 2017
Pattern matching so far: one-of types
Have used pattern-matching for one-of types because we needed a way to access the values
2
datatype exp = Constant of int
| Negate of exp
| Add of exp * exp
| Multiply of exp * exp
fun eval e =
case e of
Constant i => i
| Negate e2 => ~ (eval e2)
| Add(e1,e2) => (eval e1) + (eval e2)
| Multiply(e1,e2) => (eval e1) * (eval e2)
Pattern matching with each-of types
Pattern matching also works for records and tuples:
matches the tuple value (v1,…,vn)
matches the record value {f1=v1, …, fn=vn}
(and fields can be reordered)
3
Example
This is poor style, but based on what I told you so far, the only way to use patterns
4
fun sum_triple triple =
case triple of
(x, y, z) => x + y + z
fun full_name r =
case r of
{first=x, middle=y, last=z} =>
x ^ " " ^ y ^ " " ^ z
Val-binding patterns
5
val p = e
Better example
This is okay style
6
fun sum_triple triple =
let val (x, y, z) = triple
in
x + y + z
end
fun full_name r =
let val {first=x, middle=y, last=z} = r
in
x ^ " " ^ y ^ " " ^ z
end
Function-argument patterns
A function argument can also be a pattern
Examples (great style!):
7
fun f p = e
fun sum_triple (x, y, z) =
x + y + z
fun full_name {first=x, middle=y, last=z} =
x ^ " " ^ y ^ " " ^ z
A new way to go
8
Hmm
A function that takes one triple of type int*int*int and returns an int that is their sum:
9
A function that takes three int arguments and returns an int that is their sum
fun sum_triple (x, y, z) =
x + y + z
fun sum_triple (x, y, z) =
x + y + z
See the difference? (Me neither.) ☺
The truth about functions
10
fun rotate_left (x, y, z) = (y, z, x)
fun rotate_right t = rotate_left(rotate_left t)
Nested patterns
11
Useful example: zip/unzip 3 lists
12
fun zip3 lists =
case lists of
([],[],[]) => []
| (hd1::tl1,hd2::tl2,hd3::tl3) =>
(hd1,hd2,hd3)::zip3(tl1,tl2,tl3)
| _ => raise ListLengthMismatch
fun unzip3 triples =
case triples of
[] => ([],[],[])
| (a,b,c)::tl =>
let val (l1, l2, l3) = unzip3 tl
in
(a::l1,b::l2,c::l3)
end
More examples to come (see code files)
Style
13
(Most of) the full definition
The semantics for pattern-matching takes a pattern p and a value v and decides (1) does it match and (2) if so, what variable bindings are introduced.
Since patterns can nest, the definition is elegantly recursive, with a separate rule for each kind of pattern. Some of the rules:
14
Examples
15
Exceptions
An exception binding introduces a new kind of exception
The raise primitive raises (a.k.a. throws) an exception
A handle expression can handle (a.k.a. catch) an exception
16
exception MyFirstException
exception MySecondException of int * int
raise MyFirstException
raise (MySecondException(7,9))
e1 handle MyFirstException => e2
e1 handle MySecondException(x,y) => e2
Actually…
Exceptions are a lot like datatype constructors…
17