ML-intro-2 slides

advertisement
Introduction to ML - Part 2
Kenny Zhu
What is next?

ML has a rich set of structured values







Tuples: (17, true, “stuff”)
Records: {name = “george”, age = 35}
Lists: 3::4::5::nil or [3,4]@[5]
Datatypes
Functions
And more!
We put things together in a more complex
program
An interpreter

Interpreters are usually implemented as
a series of transformers:
lexing/
parsing
stream of
characters
evaluate
abstract
syntax
print
abstract
value
stream of
characters
A little language (LL)

An arithmetic expression e is





a boolean value
an if statement (if e1 then e2 else e3)
an integer
an add operation
a test for zero (isZero e)
LL abstract syntax in ML
datatype term =
Bool of bool
| If of term * term * term
| Num of int
| Add of term * term
| IsZero of term
vertical bar
separates alternatives
-- constructors
are capitalized
-- constructors
can take a single
argument of a
particular type
type of a tuple
another eg: string * char
LL abstract syntax in ML
Add
Add (Num 2, Num 3)
Num
represents the expression “2 + 3”
2
Num
3
LL abstract syntax in ML
If
If (Bool true,
Num 0,
Add (Num 2, Num 3))
represents
Bool Num
true
Add
Num Num
0
“if true then 0 else 2 + 3”
2
3
Function declarations
function name
fun isValue t =
case t of
Num n => true
| Bool b => true
| _ => false
default pattern matches anything
function parameter
What is the type of the
parameter t? Of the function?
function name
fun isValue t =
case t of
Num n => true
| Bool b => true
| _ => false
default pattern matches anything
function parameter
What is the type of the
parameter t? Of the function?
fun isValue (t:term) : bool =
case t of
Num n => true
| Bool b => true
| _ => false
val isValue : term -> bool
ML does type inference => you need not
annotate functions yourself (but it can be helpful)
A type error
fun isValue t =
case t of
Num _ => 1
| _ => false
ex.sml:22.3-24.15 Error: types of rules don't agree [literal]
earlier rule(s): term -> int
this rule: term -> bool
in rule:
_ => false
A type error
Actually, ML may give you several errors in a row:
ex.sml:22.3-25.15 Error: types of rules don't agree [literal]
earlier rule(s): term -> int
this rule: term -> bool
in rule:
Num t2 => true
ex.sml:22.3-25.15 Error: types of rules don't agree [literal]
earlier rule(s): term -> int
this rule: term -> bool
in rule:
_ => false
A very subtle error
fun isValue t =
case t of
num => true
| _ => false
The code above type checks. But when
we test it, the function always returns “true.”
What has gone wrong?
A very subtle error
fun isValue t =
case t of
num => true
| _ => false
The code above type checks. But when
we test it, the function always returns “true.”
What has gone wrong?
-- num is not capitalized (and has no argument)
-- ML treats it like a variable pattern (matches anything!)
Exceptions
exception Error of string
fun debug s : unit = raise (Error s)
Exceptions
exception Error of string
fun debug s : unit = raise (Error s)
in SML interpreter:
- debug "hello";
uncaught exception Error
raised at: ex.sml:15.28-15.35
Evaluator
fun isValue t = ...
exception NoRule
fun eval t =
case t of
Bool _ | Num _ => t
| ...
Evaluator
...
let statement
fun eval t =
for remembering
case t of
temporary
Bool _ | Num _ => t
results
| If(t1,t2,t3) =>
let val v = eval t1 in
case v of
Bool b => if b then (eval t2) else (eval t3)
| _ => raise NoRule
end
Evaluator
exception NoRule
fun eval1 t =
case t of
Bool _ | Num _ => ...
| ...
| Add (t1,t2) =>
case (eval v1, eval v2) of
(Num n1, Num n2) => Num (n1 + n2)
| (_,_) => raise NoRule
Finishing the Evaluator
fun eval1 t =
case t of
...
| ...
| Add (t1,t2) => ...
| IsZero t => ...
be sure your
case is
exhaustive
Finishing the Evaluator
fun eval1 t =
case t of
...
| ...
| Add (t1,t2) => ...
What if we
forgot a case?
Finishing the Evaluator
fun eval1 t =
case t of
...
| ...
| Add (t1,t2) => ...
What if we
forgot a case?
ex.sml:25.2-35.12 Warning: match nonexhaustive
(Bool _ | Zero) => ...
If (t1,t2,t3) => ...
Add (t1,t2) => ...
Demo

Managing the source files for the
interpreter
More on lists: Map
fun map f l =
case l of
nil => []
l x :: l => (f x) :: (map f l)
applies the function f to every element in the list
- fun add1 x = x + 1;
- map add1 [1,2,3];
> val it = [2,3,4] : int list
More on lists: Fold
fun fold f init l =
case l of
nil => init
| x :: l => f (x, fold f init l)
applies function f (x, y) on the elements of l and the result
from previous application recursively
- fun sum (x, y) = x + y;
- foldr sum 0 [1,2,3,4];
val it = 10 : int
Download