more ml compiling techniques david walker. today more data structures lists more functions more...
TRANSCRIPT
More ML
Compiling TechniquesDavid Walker
Today More data structures
lists More functions More modules
Lists Lists are created with
nil (makes empty list) head :: tail (makes a longer list)
5 :: nil : int list
elementlist of elements
Lists Lists are created with
nil (makes empty list) head :: tail (makes a longer list)
4 :: (5 :: nil) : int list
elementlist of elements
Lists Lists are created with
nil (makes empty list) head :: tail (makes a longer list)
3 :: 4 :: (5 :: nil) : int list
elementlist of elements
Lists Lists are created with
3 :: (4 :: (5 :: nil)) : int list
3 :: 4 :: 5 :: nil : int list
(true, 1) :: (false, 2) :: nil : (bool * int) list
(3 :: nil) :: (2 :: nil) :: nil : (int list) list
Lists Lists:
3 :: [] : int list
3 :: [4, 5] : int list
[true] : bool list
a different wayof writing “nil”
a different wayof writing a list
Lists Bad List:
[4]::3;
???
Lists Bad List:
[4]::3;
stdIn:1.1-2.2 Error: operator and operand don't agree [literal]
operator domain: int list * int list list operand: int list * int in expression: (4 :: nil) :: 3
Lists Bad List:
[true, 5];
???
Lists Bad List:
[true, 5];
stdIn:17.1-17.9 Error: operator and operand don't agree [literal]
operator domain: bool * bool list operand: bool * int list in expression: true :: 3 :: nil
List Processing
Functions over lists are usually defined by pattern matching on the structure of a list
Hint: often, the structure of a function isguided by the type of the argument (recall eval)
fun length l = case l of nil => 0 l _ :: l => 1 + (length l)
List Processing
fun map f l = case l of nil => [] l x :: l => (f x) :: (map f l)
What does it do?
Two arguments f and l
List Processing
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
List Processing
fun fold f a l = case l of nil => a l x :: l => f (fold f a l) x
another incredibly useful function
what does it do? use it to write map.
ML is all about functions There are many different ways to
define functions! I almost always use “fun f x = ...” When I am only going to use a
function once and it is not recursive, I write an anonymous function: (fn x => ...)
Anonymous functions
val n = 3
val isValue = (fn t => case t of Bool _ => true | t => false)
binds a variable (n)to a value (3)
binds a variable(isValue)
to the anonymous function valuefn keyword
introducesanonymousfun
Anonymous functions
fun map f l = case l of nil => [] l x :: l => (f x) :: (map f l)
fun addlist x l = map (fn y => y + x) l
anonymous functions
Anonymous functions
type ifun = int -> int
val intCompose : ifun * ifun -> ifun = ...
fun add3 x = intCompose ((fn x => x + 2), (fn y => y + 1)) x
a pair of anonymous functions
a type definition (very convenient)
Anonymous functions
type ifun = int -> int
val intCompose : ifun * ifun -> ifun = fn (f,g) => (fn x => f (g x))
fun add3 x = intCompose ((fn x => x + 2), (fn y => y + 1)) x
result is a function!
argument is pair of functionspatternmatchagainstarg
Another way to write a function
fun f x = ........
can be written as:
val f = (fn x => ......)
provided the function is not recursive;f does not appear in ........
Another way to write a function
fun f x = ....
can always be written as:
val rec f = (fn x => ...f can be used here...)
keyword rec declares a recursive function value
Yet another way to write a function
fun isValue Num n = true | isValue (Bool b) = true | isValue (_) = false
This is just an abbreviation for
fun isValue t = case t of Num n => true | Bool b => true | _ => false
Yet another way to create a type errorfun isValue 0 = true | isValue (Bool b) = true | isValue (_) = false
ex.sml:9.1-11.29 Error: parameter or result constraints of clauses don't agree [literal] this clause: term -> 'Z previous clauses: int -> 'Z in declaration: isValue = (fn 0 => true | Bool b => true | _ => false)
Parametric Polymorphism Functions like compose work on objects
of many different types
val compose = fn f => fn g => fn x => f (g x)
compose (fn x => x + 1) (fn x => x + 2)
compose not (fn x => x < 17)
Parametric Polymorphism Functions like compose work on objects
of many different types
val compose = fn f => fn g => fn x => f (g x)
compose not (fn x => x < 17)
compose (fn x => x < 17) not BAD!!
Parametric Polymorphism Functions like compose work on objects
of many different types
val compose = fn f => fn g => fn x => f (g x)
compose: (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
Note: type variables are written with ‘
a type variablestands forany type
Parametric Polymorphism Functions like compose work on objects
of many different types
compose: (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
compose: (int -> ‘b) -> (‘c -> int) -> (‘c -> ‘b)
can be used as if it had the type:
Parametric Polymorphism Functions like compose work on objects
of many different types
compose: (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
compose: ((int * int) -> ‘b) -> (‘c -> (int * int)) -> (‘c -> ‘b)
can be used as if it had the type:
Parametric Polymorphism Functions like compose work on objects
of many different types
compose: (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
compose: (unit -> int) -> (int -> unit) -> (int -> int)
can be used as if it had the type:
Parametric Polymorphism
compose not : ??
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
Parametric Polymorphism
compose not : ??
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
type of compose’s argument must equalthe type of not:bool -> bool == (‘a -> ‘b)
Parametric Polymorphism
compose not : ??
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
‘a must be bool‘b must be bool as well(in this use of compose)
therefore:
Parametric Polymorphism
compose not : (‘c -> bool) -> (c’ -> bool)
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
‘a = bool‘b = bool
Parametric Polymorphism
compose not : (‘c -> bool) -> (c’ -> bool)
(compose not) not : bool -> bool
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
Parametric Polymorphism
compose not : (‘c -> bool) -> (c’ -> bool)
(compose not) not : ??
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)not : bool -> bool
Parametric Polymorphism
compose (fn x => x) : ?
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
Parametric Polymorphism
compose (fn x => x) : ?
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
‘d -> ‘d
Parametric Polymorphism
compose (fn x => x) : ?
compose : (‘a -> ‘b) -> (‘c -> ‘a) -> (‘c -> ‘b)
‘d -> ‘d
must be the same
ie:
‘a = ‘d‘b = ‘d
Parametric Polymorphism
compose (fn x => x) : ?
compose : (‘d -> ‘d) -> (‘c -> ‘d) -> (‘c -> ‘d)
‘d -> ‘d
must be the same
ie:
‘a = ‘d‘b = ‘d
Parametric Polymorphism
compose (fn x => x) : ?
compose : (‘d -> ‘d) -> (‘c -> ‘d) -> (‘c -> ‘d)
‘d -> ‘d
(‘c -> ‘d) -> (‘c -> ‘d)
What is the type of map?
fun map f l = case l of nil => [] l x :: l => (f x) :: (map f l)
What is the type of map?
fun map f l = case l of nil => [] l x :: l => (f x) :: (map f l)
Hint: top-level shape is:
.... -> ... -> ....
What is the type of map?
fun map f l = case l of nil => [] l x :: l => (f x) :: (map f l)
Solution:
(‘a -> ‘b) -> ‘a list -> ‘b list
ML Modules Signatures
Interfaces Structures
Implementations Functors
Parameterized structures Functions from structures to
structures
Structures
structure Queue = struct
type ‘a queue = ‘a list * ‘a listexception Emptyval empty = (nil, nil)fun insert (x, q) = …fun remove q = …
end
Structures
structure Queue = struct
type ‘a queue = ‘a list * ‘a listexception Empty
...end
fun insert2 q x y = Queue.insert (y, Queue.insert (q, x))
Structures
structure Queue = struct
...end
structure Q = Queue
fun insert2 q x y = Q.insert (y, Q.insert (q, x))
convenientabbreviation
Structures
structure Queue = struct
type ‘a queue = ‘a list * ‘a list...
end
fun insert2 (q1,q2) x y : ‘a queue = (x::y::q1,q2)
by default,all componentsof the structure may be used
-- we know the type ‘a queue
Signatures
signature QUEUE =sig
type ‘a queueexception Emptyval empty : ‘a queueval insert : ‘a * ‘a queue -> ‘a queueval remove : ‘a queue -> ‘a * ‘a
queue end
abstract type
-- we don’t know the type ‘a queue
Information hiding
signature QUEUE = sig type ‘a queue ... end
structure Queue :> QUEUE = struct type ‘a queue = ‘a list * ‘a list val empty = (nil, nil) … end
fun insert2 (q1,q2) x y : ‘a queue = (x::y::q1,q2)
does nottype check
Signature Ascription Opaque ascription
Provides abstract typesstructure Queue :> QUEUE = …
Transparent ascription A special case of opaque ascription Hides fields but does not make types
abstractstructure Queue_E : QUEUE = …
SEE Harper, chapters 18-22 for more on modules
Other things functors (functions from structures
to structures) references (mutable data structures)
ref e; !e; e1 := e2 while loops, for loops arrays (* comments (* can be *) nested *) a bunch of other stuff...
Last Things Learning to program in SML can be
tricky at first But once you get used to it, you
will never want to go back to imperative languages
Check out the reference materials listed on the course homepage