# More ML Compiling Techniques David Walker. Today More data structures lists More functions More modules.

## Presentation on theme: "More ML Compiling Techniques David Walker. Today More data structures lists More functions More modules."— Presentation transcript:

More ML Compiling Techniques David 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 element list of elements

Lists Lists are created with nil (makes empty list) head :: tail(makes a longer list) 4 :: (5 :: nil) : int list element list of elements

Lists Lists are created with nil (makes empty list) head :: tail(makes a longer list) 3 :: 4 :: (5 :: nil) : int list element list 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 way of writing nil a different way of writing a list

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 is guided 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 value fn keyword introduces anonymous fun

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 functions pattern match against arg

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 error fun 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 variable stands for any 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 composes argument must equal the 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 list exception Empty val empty = (nil, nil) fun insert (x, q) = … fun remove q = … end

Structures structure Queue = struct type a queue = a list * a list exception 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)) convenient abbreviation

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 components of the structure may be used -- we know the type a queue

Signatures signature QUEUE = sig type a queue exception Empty val empty : a queue val insert : a * a queue -> a queue val 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 not type check

Signature Ascription Opaque ascription Provides abstract types structure Queue :> QUEUE = … Transparent ascription A special case of opaque ascription Hides fields but does not make types abstract structure 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

Download ppt "More ML Compiling Techniques David Walker. Today More data structures lists More functions More modules."

Similar presentations