Title: Introduction to ML
1Introduction to ML
- A Quasi-Functional Language
- With Strong Typing
- And Type Inference
2Example of Interactive Session
- Conventional syntax
- val x 5 (user input )
- val x 5 int (system
response) - fun len lis if (null lis) then 0 else 1
len (tl lis) - val len fn a list - int
- Type inference for local entities
- x x x
- val it 125 int ( it denotes
last computation)
3Operations on lists
- Similar to LISP, with (hd, tl, ) instead of
(car, cdr, cons) -
- - fun append (x, y) if null (x)
then y - else
hd (x) append (tl (x), y) - val append fn a list a list -
a list - ( a function that takes a pair of lists and
yields a list ) - - fun upto (m, n)
- if m n then else m upto
(m1, n) - val upto fn int int - int list
- ( a function that takes two numbers and yields a
list )
4Patterns
- A simple mechanism to describe and name parts of
a structure fun prod 1 ( if list is
empty ) - prod (nns) n prod (ns) ( n is
first element ) - A list can be described by its head and its tail
- fun maxl m int m
- maxl (mnns) if m n then maxl (m
ns) -
else maxl (n ns)
5Recursion and iteration
- A function that returns the first i elements of a
list - fun take ( , I)
- take (xxs, I) if I 0 then
xtake (xs, I - 1) else - Non-recursive version introduce an accumulator
argument - fun itake ( , _, taken) taken (
_ is pattern for anything ) - itake (xxs, I, taken)
- if I 0 then itake (xs, I -
1, xtaken) - else taken
- var rtake fn a list int a
list - a list
6A classic in functional form quicksort
- fun quick
- quick xreal x
- quick (abs)
- let fun partition (left, right, )
- (quick
left) _at_ (quick right) - partition (left, right,
xxs) - if x (xleft, right, xs)
- else
partition (left, x right, xs) - in
- partition (a, , bs)
end - val quick fn real list - real list
- note this assumes no repeating elements
7A single formal is sufficient
- If function takes more than one argument, say
that it takes a single composite one - fun exp (x, n) if n 0 then 1
- else x
exp (x, n-1) - val exp fn int int - int
- Single argument is a tuple (int, int)
- Can also define records with named components
8The type system
- Primitive types bool, int, char, real, string
- Constructors list, array, product (record),
function - an expression has a corresponding type expression
- the interpreter builds the type expression for
each input - type checking requires that type expression of
functions and their arguments match, and that
type expression of context match result of
function
9Boolean Values
- Two values
- true and false
- The usual set of logical operators etc
10Integers (type int)
- Can notate in either decimal or hex (0xaa)
- Negative sign uses
- This is because unary minus is an operator
- But is part of the number
- Most languages dont have negative literals
- Which is an odd corner
- All the usual arithmetic operators
11Unsigned (type word)
- A distinct type from int
- Notated as 123w or 0wxff
- Must be able to tell type of literal
- From the literal itself
- Without any context
- Usual arithmetic operators
- (but not abs, unary minus)
12Floating-point Type (real)
- Notated with either a decimal point and a
fractional part or an exponent or both - 3.45
- 3E4
- Usual arithmetic operators
- Note that usual arithmetic operators are
overloaded, but must be able to tell type! - No implicit conversions between numeric types,
functions in library used instead.
13String Type
- String is a primitive
- Not a vector of characters
- Usual notation (like Ada or C)
- Carret () is concatenation
- There is also a type char for single chars
- Function str makes char into a string
- Note everything is case sensitive
- All keywords lower case
14Example of Simple Arithmetic
- Zeller function for day of the week
- val floor Real.floorval real
Real.fromIntval zc fn (d, m, y, c)
(floor (2.61 real (m) - 0.2) d y y
div 4 c div 4 - 2 c) mod 7 - Note that the following are equivalent val zc
fn fun zc
15Local Variables
- Zeller function rewritten (floor, real local)
- local val floor Real.floor val real
Real.fromIntin val zc fn (d, m, y, c)
(floor (2.61 real (m) - 0.2) d y y
div 4 c div 4 - 2 c) mod 7end
16Use of let
- Local allows decls used in other decls
- Let allows decls used in expressions
- ( Radix for non-negative nums ) val rec radix
fn (n, base) let val b size base
val digit fn n str (String.sub (base,
n)) val radix' fn (true, n)
digit n (false, n) radix (n div b,
base) digit (n mod b) in radix' (n
b, n) end
17Block structure and nesting
- Example of nesting
- fun findroot (a, x, acc)
- ( standard Newton-Raphson )
- let val nextx (a / x x)
/ 2.0 (next approximation ) - in
- if abs (x - nextx) nextx
-
else findroot (a, nextx, acc) - end
- (tail recursion rather than
iteration )
18What is an ML Program
- So far we have seen functions and expressions,
but what is an ML program? - Answer, a bunch of definitions and an expression
to evaluate, typically - let declarations in expression
end
19Type inference
- fun incr x x 1
- val incr fn int - int
- because of its appearance in (x1), x must be
integer - fun add2 x incr (incr x)
- val add2 fn int - int
- incr returns an integer, so add2 does as well
- x is argument of incr, so must be integer
- val wrong 10.5 incr 7
- Error operator and operand dont
agree
20Polymorphism
- fun len x if null x then 0
- else 1 len (tl x)
- Works for any kind of list. What is its type
expression? - val len fn a list - int
- a denotes a type variable. Implicit universal
quantification - for any a, len applies to a list of as.
- fun copy lis if null lis then nil
- else hd (lis)
copy (tl lis)
21Functionals
- fun exists pred false
- exists pred (xxs) (pred x) orelse
exists pred xs - ( pred is a predicate a function that
delivers a boolean ) - val exists fn (a - bool) - a list
- bool - fun all pred true
- all pred (xxs) (pred x) andalso all
pred xs val all fn (a - bool) - a
list - bool - fun filter pred
- filter (xxs)
- if pred x then x filter pred xs
- else filter pred xs
- val filter fn (a - bool) - a list
a list
22Currying partial bindings
- a b c means (a b) c (a b) yields a
function that is applied to c - fun app2 x y if null x then y
- else (hd x)
app2 (tl x) y - val app2 fn a list - a list -
a list - (a function that given a list yields a function
that takes a list and yields a list ) - val ap123 app2 1, 2, 3
- val ap123 fn int list - int
list - ap123 10, 20, 30
- val it 1, 2, 3, 10, 20, 30
23Type inference and unification
- Type expressions are built by solving a set of
equations - fun reduce f lis init if null lis
then init - else f ((hd lis),
reduce f (tl lis) init)) - null a list - bool
- hd b list - b
- tl c list - c list
- apply (d - e) d - e
(function application) - let b be the type of init. Let a be the element
type of lis. - Then f takes an a and a b and returns a b.
- val reduce fn (a - b - b)
- (a list) - b - b
24Unification algorithm
- A type variable can be unified with another
variable - a unifies with b a and b are
the same - A type variable can be unified with a constant
- a unifies with int all occurences
of a mean int - A type variable can be unified with an expression
- a unifies with b list
- a does not unify with a list
- A constant can be unified with itself int is int
- An expression can be unified with another
expression if the constructors are identical and
if the arguments can be unified (recursive) - (int - int) list unifies with a list, a is a
function on integers
25Type system does not handle overloading well
- fun plus x y x y
- operator is overloaded, cannot be resolved from
context (error in some versions, defaults to int
in others) - The type system can decide that a function takes
a but not that it takes an int or real - Can use explicit typing to select interpretation
- fun mix (x, y ,z) x y zreal
- mix (real real real) - real
26Parametric polymorphism vs. generics
- A function whose type expression has type
variables applies to an infinite set of types. - Equality of type expressions means structural
equivalence. - All applications of a polymorphic function use
the same body no need to instantiate. - let val ints 1, 2, 3
- val strs this, that
- in
- len ints len strs ( int list -
int, string list - int ) - end
- val it 5 int
27User-defined types and inference
- A user-defined type introduces constructors
- datatype tree leaf of int node of tree
tree - leaf and node are type constructors
- can define functions by pattern
- fun sum (leaf (t)) t
- sum (node (t1, t2)) sum t1 sum
t2 - val sum fn tree - int
28Parameterized datatypes
- fun flatten (leaf (t)) t
- flatten (node (t1, t2)) flatten (t1)
_at_ flatten (t2) - flatten tree - int list
- datatype a gentree leaf of a
- node of a
gentree a gentree - val names node (leaf (this), leaf
(that)) - Here names is of type string gentree
29Programming in the large in ML
- Need mechanisms for
- Modularization
- Information hiding
- Parametrization of interfaces
- While retaining type inference
- Modules like packages / namespaces
- Signatures like package specifications /Java
interfaces - Functors like generics with formal packages
30Structures
- structure Complex
- struct
- type t real real
- val zero (0.0, 0.0)t (qualification
may be needed ) - val i (0.0, 1.0)
- fun sum ((x, y), (x1, y1)) (xx1,
yy1)t - fun prod ((x, y), (x1, y1)) (xx1 yy1,
xy1 yx1)t - fun inv ((x, y))
- let val den xx yy
- in
- (x / den, y / den) t
- end
- fun quo (z, z1) prod (z, inv (z1))t
- end
31Using a structure
- use (complex.ml)
- signature Complex
- Complex.prod (Complex.i, Complex.i)
- val it (1.0, 0.0)
-
- val pi4 (0.707, 0.707)
- val pi4 real real structural
equivalence - Complex.prod (pi4, pi4)
- val it Complex.t
32Signatures
- Interface description without implementation
- signature CMPLX
- sig
- type t
- val zero t
- val i t
- val sum t t - t
- val diff t t - t
- val prod t t - t
- val inv t - t
- val quo t t - t
- end
33Multiple implementations
- structure complex1 CMPLX
- struct
- type t realreal ( cartesian
representation ) - val zero (0.0, 0.0)
- val i (0.0, 1.0)
-
- Structure ComplexPolar CMPLX
- Struct
- type t realreal (polar
representation) - val zero (0.0, 0.0)
- val pi 3.141592
- val i (0.0, pi / 2.0)
34Information Hiding
- Only signature should be visible
- Declare structure to be opaque
- structure polar CMPLX .
- (Structure can be opaque or transparent depending
on context). - Can export explicit constructors and equality for
type. Otherwise, equivalent to limited private
types in Ada. - Can declare as eqtype to export equality
35Functors
- Structures and signatures are not first-class
objects. - A program (structure) can be parametrized by a
signature - functor testComplex (C CMPLX)
- struct
- open C (equivalent
to use clause) - fun FFT..
- end
- structure testPolar testComplex
(Complexpolar) - ( equivalent to instantiation with a
package )
36Imperative Programming in ML
- A real language needs operations with side
effects, state, and variables - Need to retain type inference
- - val p ref 5
- val p ref 5 int ref ( ref is a
type constructor) - - !p 2 (
dereference operation ) - val it 10 int
- - p !p 3
- val it ( ) unit (
assignment has no value ) - References are equality types (pointer equality)
37The library
- Lists structure useful Operations on Lists
- Listpairs structure, operates on 2 lists,e.g.
- ListPair.unzip ('a 'b) list - 'a list 'b
list ListPair.zip 'a list 'b list - ('a
'b) list - Vector operations (allow indexing)
38Lazy Evaluation
- Delay evaluation till value needed
- Some languages do this by default (Haskel and
Miranda are examples) - Advantage is avoiding evaluating stuff that is
never needed, and aids correctness - fun take x y y
- Are the following equivalent?
- expr1
- Take expr2 expr1
- No, because expr2 might not terminate
- ML is strict (but laziness can be simulated using
functional forms that delay evaluation) - There are forms that assist in this approach
(e.g. delayed)
39Abstract Data Types
- abstype 'a set null ins of 'a 'a setwith
val emptyset null val addset ins fun
memberset (x, null) false memberset (x,
ins (v, s)) x v orelse memberset (x, s)
local fun subset (null, _) true
subset (ins (x, s1), s2)
memberset (x, s1) andalso subset (s1, s2) in
fun equalset (s1, s2) subset (s1, s2)
andalso subset (s2, s1) end end