a fourth look at ml
DESCRIPTION
A Fourth Look At ML. Chapter 11 Type-Safe Data Structures. Type Definitions. Predefined, but not primitive in ML: Type constructor for lists: Defined for ML in ML. datatype bool = true | false;. datatype 'element list = nil | :: of 'element * 'element list. Outline. Enumerations - PowerPoint PPT PresentationTRANSCRIPT
A Fourth Look At MLA Fourth Look At MLChapter 11Type-Safe Data Structures
Chapter Eleven Modern Programming Languages 1
Type DefinitionsType DefinitionsPredefined, but not primitive in
ML:
Type constructor for lists:
Defined for ML in ML
Chapter Eleven Modern Programming Languages 2
datatype bool = true | false;
datatype 'element list = nil | :: of 'element * 'element list
OutlineOutlineEnumerationsData constructors with
parametersType constructors with
parametersRecursively defined type
constructorsFarewell to ML
◦We hardly knew ye!
Chapter Eleven Modern Programming Languages 3
Defining Your Own TypesDefining Your Own TypesNew types can be defined using
the keyword datatypeThese declarations define both:
◦type constructors for making new (possibly polymorphic) types
◦data constructors for making values of those new types
Chapter Eleven Modern Programming Languages 4
ExampleExample
day is the new type constructor and Mon, Tue, etc. are the new data constructors
Why “constructors”? In a moment we will see how both can have parameters…
Chapter Eleven Modern Programming Languages 5
- datatype day = Mon | Tue | Wed | Thu | Fri | Sat | Sun;datatype day = Fri | Mon | Sat | Sun | Thu | Tue | Wed- fun isWeekDay x = not (x = Sat orelse x = Sun);val isWeekDay = fn : day -> bool- isWeekDay Mon;val it = true : bool- isWeekDay Sat;val it = false : bool
No ParametersNo Parameters
The type constructor day takes no parameters: it is not polymorphic, there is only one day type
The data constructors Mon, Tue, etc. take no parameters: they are constant values of the day type
Capitalize the names of data constructors
Chapter Eleven Modern Programming Languages 6
- datatype day = Mon | Tue | Wed | Thu | Fri | Sat | Sun;datatype day = Fri | Mon | Sat | Sun | Thu | Tue | Wed
Strict TypingStrict Typing
ML is strict about these new types, just as you would expect
Unlike C enum, no implementation details are exposed to the programmer
Chapter Eleven Modern Programming Languages 7
- datatype flip = Heads | Tails;datatype flip = Heads | Tails- fun isHeads x = (x = Heads);val isHeads = fn : flip -> bool- isHeads Tails;val it = false : bool- isHeads Mon;Error: operator and operand don't agree [tycon mismatch] operator domain: flip operand: day
Data Constructors In Data Constructors In PatternsPatterns
You can use the data constructors in patterns
In this simple case, they are like constantsBut we will see more general cases next…
Chapter Eleven Modern Programming Languages 8
fun isWeekDay Sat = false| isWeekDay Sun = false| isWeekDay _ = true;
The The orderorder Datatype DatatypeUsed with pre-defined compare
functions◦Int.compare( )◦Real, String, Char, Time, Date, …
datatype order = LESS | GREATER | EQUAL;
- Real.compare(1.0,2.0);
val it = LESS : order- Char.compare(#"b", #"a");
val it = GREATER : order
Chapter Eleven Modern Programming Languages 9
OutlineOutlineEnumerationsData constructors with
parametersType constructors with
parametersRecursively defined type
constructorsFarewell to ML
Chapter Eleven Modern Programming Languages 10
WrappersWrappersYou can add a parameter of any type to
a data constructor, using the keyword of:datatype exint = Value of int | PlusInf | MinusInf;
In effect, such a constructor is a wrapper that contains a data item of the given type
Chapter Eleven Modern Programming Languages 11
PlusInfValue
36
MinusInf Value26
Value38
Some thingsof type exint:
Value is a data constructor that takes a parameter: the value of the int to store
It looks like a function that takes an int and returns an exint containing that int
Chapter Eleven Modern Programming Languages 12
- datatype exint = Value of int | PlusInf | MinusInf;datatype exint = MinusInf | PlusInf | Value of int- PlusInf;val it = PlusInf : exint- MinusInf;val it = MinusInf : exint- Value;val it = fn : int -> exint (* Function notation! *)- Value 3;val it = Value 3 : exint
A A ValueValue Is Not An Is Not An intint
Value 5 is an exintIt is not an int, though it contains
oneHow can we get the int out again?By pattern matching…
Chapter Eleven Modern Programming Languages 13
- val x = Value 5;val x = Value 5 : exint- x+x;Error: overloaded variable not defined at type symbol: + type: exint
Patterns With Data Patterns With Data ConstructorsConstructors
To recover a data constructor’s parameters, use pattern matching
So Value is no ordinary function: ordinary functions can't be pattern-matched this way
Chapter Eleven Modern Programming Languages 14
- val (Value y) = x;Warning: binding not exhaustive Value y = ...val y = 5 : int
An Exhaustive PatternAn Exhaustive Pattern
Like most uses of the match construct, you get a warning if it is not exhaustive
An exint can be a PlusInf, a MinusInf, or a Value
This one says what to do in all cases
Chapter Eleven Modern Programming Languages 15
- val s = case x of = PlusInf => "infinity" |= MinusInf => "-infinity" | = Value y => Int.toString y;val s = "5" : string
Pattern-Matching FunctionPattern-Matching Function
Pattern-matching function definitions are especially important when working with your own datatypes
Chapter Eleven Modern Programming Languages 16
- fun square PlusInf = PlusInf= | square MinusInf = PlusInf= | square (Value x) = Value (x*x);val square = fn : exint -> exint- square MinusInf;val it = PlusInf : exint- square (Value 3);val it = Value 9 : exint
Exception Handling (A Exception Handling (A Peek)Peek)
Patterns are also used in ML for exception handling, as in this example
Chapter Eleven Modern Programming Languages 17
- fun square PlusInf = PlusInf= | square MinusInf = PlusInf= | square (Value x) = Value (x*x)= handle Overflow => PlusInf;val square = fn : exint -> exint- square (Value 10000);val it = Value 100000000 : exint- square (Value 100000);val it = PlusInf : exint
OutlineOutlineEnumerationsData constructors with
parametersType constructors with
parametersRecursively defined type
constructorsFarewell to ML
Chapter Eleven Modern Programming Languages 18
Partial FunctionsPartial FunctionsA function that is not defined for
all values of its domain type is called a partial function
Examples:◦1/x; functions that expect a non-null
pointerIn ML, the option data type
indicates undefined valuesdatatype ‘a option = NONE |
SOME of ‘a;Chapter Eleven Modern Programming Languages 19
Type Constructors With Type Constructors With ParametersParameters
Type constructors can also use parameters: datatype 'a option = NONE | SOME of 'a;
The parameters of a type constructor are type variables, which are used in the data constructors
The result: a new polymorphic type
Chapter Eleven Modern Programming Languages 20
NONE
SOME"Hello"
Values of typestring option
SOME"world"
NONE
SOME1.5
Values of type real option
SOME123.4
Parameter Before NameParameter Before Name
Type constructor parameter comes before the type constructor name:datatype 'a option = NONE | SOME of 'a;
We have types 'a option and int option, just like 'a list and int list
Chapter Eleven Modern Programming Languages 21
- SOME 4;val it = SOME 4 : int option- SOME 1.2;val it = SOME 1.2 : real option - SOME "pig";val it = SOME "pig" : string option
Uses For Uses For optionoptionPredefined type constructor in MLUsed by predefined functions (or your
own) when the result is not always defined
Chapter Eleven Modern Programming Languages 22
- fun optdiv a b == if b = 0 then NONE else SOME (a div b);val optdiv = fn : int -> int -> int option- optdiv 7 2;val it = SOME 3 : int option- optdiv 7 0;val it = NONE : int option
Working with Working with optionoptionRetrieve the value of an option,
other than NONE, with valOfProvide a default value for NONE
with getOptval x = SOME 2 : int option
- valOf x;
val it = 2 : int
- getOpt (x,0);
val it = 2 : int
- getOpt (NONE, 0);
val it = 0 : int
See fact.smlChapter Eleven Modern Programming Languages 23
Longer Example: Longer Example: bunchbunch
An 'x bunch is either a thing of type 'x, or a list of things of type 'x
As usual, ML infers types:
Chapter Eleven Modern Programming Languages 24
datatype 'x bunch = One of 'x | Group of 'x list;
- One 1.0;val it = One 1.0 : real bunch- Group [true,false];val it = Group [true,false] : bool bunch
Example: PolymorphismExample: Polymorphism
ML can infer bunch types, but does not always have to resolve them, just as with list types
Chapter Eleven Modern Programming Languages 25
- fun size (One _) = 1= | size (Group x) = length x;val size = fn : 'a bunch -> int- size (One 1.0);val it = 1 : int- size (Group [true,false]);val it = 2 : int
Example: No PolymorphismExample: No Polymorphism
We applied the + operator (through foldr) to the list elements
So ML knows the parameter type must be int bunch
Chapter Eleven Modern Programming Languages 26
- fun sum (One x) = x= | sum (Group xlist) = foldr (op +) 0 xlist;val sum = fn : int bunch -> int- sum (One 5);val it = 5 : int- sum (Group [1,2,3]);val it = 6 : int
OutlineOutline
EnumerationsData constructors with parametersType constructors with parametersRecursively defined type
constructorsFarewell to ML
Chapter Eleven Modern Programming Languages 27
Recursively Defined Type Recursively Defined Type ConstructorsConstructorsThe type constructor being defined may
be used in its own data constructors: datatype intlist = INTNIL | INTCONS of int * intlist;
Chapter Eleven Modern Programming Languages 28
Some values oftype intlist:
INTNIL
INTCONS
the empty list
INTNIL 1
the list [1]
INTCONS INTNIL 2
INTCONS
1
the list [1,2]
Constructing Those ValuesConstructing Those Values
Chapter Eleven Modern Programming Languages 29
- INTNIL;val it = INTNIL : intlist- INTCONS (1,INTNIL);val it = INTCONS (1,INTNIL) : intlist- INTCONS (1,INTCONS(2,INTNIL));val it = INTCONS (1,INTCONS (2,INTNIL)) : intlist
INTNIL
INTCONS
the empty list
INTNIL 1
the list [1]
INTCONS INTNIL 2
INTCONS
1
the list [1,2]
An An intlistintlist Length Length FunctionFunction
A length functionMuch like you would write for native
listsExcept, of course, that native lists are
not always lists of integers…
Chapter Eleven Modern Programming Languages 30
fun intlistLength INTNIL = 0 | intlistLength (INTCONS(_,tail)) = 1 + (intListLength tail);
fun listLength nil = 0 | listLength (_::tail) = 1 + (listLength tail);
Parametric List TypeParametric List Type
A parametric list type, almost like the predefined list
ML handles type inference in the usual way:
Chapter Eleven Modern Programming Languages 31
datatype 'element mylist = NIL | CONS of 'element * 'element mylist;
- CONS(1.0, NIL);val it = CONS (1.0,NIL) : real mylist- CONS(1, CONS(2, NIL));val it = CONS (1,CONS (2,NIL)) : int mylist
Some Some mylistmylist Functions Functions
This now works almost exactly like the predefined list type constructor
Of course, to add up a list you would use foldr…
Chapter Eleven Modern Programming Languages 32
fun myListLength NIL = 0 | myListLength (CONS(_,tail)) = 1 + myListLength(tail);
fun addup NIL = 0 | addup (CONS(head,tail)) = head + addup tail;
A A foldrfoldr For For mylistmylist
Definition of a function like foldr that works on 'a mylist
Can now add up an int mylist x with: myfoldr (op +) 0 x
One remaining difference: :: is an operator and CONS is not
Chapter Eleven Modern Programming Languages 33
fun myfoldr f c NIL = c | myfoldr f c (CONS(a,b)) = f(a, myfoldr f c b);
Defining OperatorsDefining Operators
ML allows new operators to be definedLike this:
Chapter Eleven Modern Programming Languages 34
- infixr 5 CONS;infixr 5 CONS- 1 CONS 2 CONS NIL;val it = 1 CONS 2 CONS NIL : int mylist
Chinese BoxesChinese BoxesNested, square boxes
◦like Russian DollsEach box has a size (length of
side) and a color
Chapter Eleven Modern Programming Languages 35
datatype color = Red | Green | Blue;datatype 'a cbox = Contents of 'a option | Trio of int * color * 'a cbox;
Chinese Box FunctionsChinese Box FunctionsSee cbox.smlSee cbox.sml
makebox: int * color * 'a cbox -> 'a cbox
boxcount: 'a cbox -> inttracebox: 'a cbox -> unit
◦ prints the box attributes outside-inopenbox: 'a cbox -> 'a option
◦ returns the inner contentsinsert: int * color * 'a cbox -> 'a cbox
makebox2: (int * color) list * 'a option -> 'a cbox
Chapter Eleven Modern Programming Languages 36
One More FunctionOne More Functiondifflist = fn : 'a cbox -> int list
- difflist b;val it = [1,1,1,1] : int list
Chapter Eleven Modern Programming Languages 37
fun difflist1 (Trio (s, _, Trio(s2,c,box))) = (s-s2)::difflist1 (Trio(s2,c,box))| difflist1 _ = nil;
Layered Patterns with Layered Patterns with asas
Chapter Eleven Modern Programming Languages 38
fun difflist (Trio (s,_,b as Trio(s2,_,_))) = (s-s2)::difflist b| difflist _ = nil;
Polymorphic Binary TreePolymorphic Binary Treedatatype 'data tree = Empty | Node of 'data tree * 'data * 'data tree;
Chapter Eleven Modern Programming Languages 39
Some values oftype int tree:
Empty
Node
the empty tree
2
the tree 2
Empty Empty
Node 3 Empty Empty
Node 1
the tree 2
Empty Empty 2
1 3
Node
Constructing Those ValuesConstructing Those Values
Chapter Eleven Modern Programming Languages 40
- val treeEmpty = Empty;val treeEmpty = Empty : 'a tree- val tree2 = Node(Empty,2,Empty);val tree2 = Node (Empty,2,Empty) : int tree- val tree123 = Node(Node(Empty,1,Empty),= 2,= Node(Empty,3,Empty));
Increment All ElementsIncrement All Elements
Chapter Eleven Modern Programming Languages 41
fun incall Empty = Empty | incall (Node(x,y,z)) = Node(incall x, y+1, incall z);
- incall tree123;val it = Node (Node (Empty,2,Empty), 3, Node (Empty,4,Empty)) : int tree
Add Up The ElementsAdd Up The Elements
Chapter Eleven Modern Programming Languages 42
fun sumall Empty = 0 | sumall (Node(x,y,z)) = sumall x + y + sumall z;
- sumall tree123;val it = 6 : int
Convert To List Convert To List (Polymorphic)(Polymorphic)
Chapter Eleven Modern Programming Languages 43
(* In-order traversal *)
fun listall Empty = nil | listall (Node(x,y,z)) = listall x @ y :: listall z;
- listall tree123;val it = [1,2,3] : int list
Tree SearchTree Search
Chapter Eleven Modern Programming Languages 44
fun isintree x Empty = false | isintree x (Node(left,y,right)) = x=y orelse isintree x left orelse isintree x right;
- isintree 4 tree123;val it = false : bool- isintree 3 tree123;val it = true : bool
Infinite ListsInfinite Listsaka aka ““StreamsStreams””
It is possible, and often useful, to define infinite lists
The elements are computed on demand
Allows a high degree of separation between software components (functions)
Chapter Eleven Modern Programming Languages 45
The The unitunit Data Type Data TypeLike void in C++
◦a “nothing” return type, or◦an “empty” parameter list
Denoted by ( ) in ML
Chapter Eleven Modern Programming Languages 46
- print "hello\n";helloval it = () : unit- fun f () = "goodbye";val f = fn : unit -> string- f();val it = "goodbye" : string
Nodes for Infinite Linked Nodes for Infinite Linked ListsListsRecall the list type definition:
The first node slot is the dataThe second is a “pointer” to the
tailFor infinite lists, we will delay the
evaluation of the tail:
Chapter Eleven Modern Programming Languages 47
datatype 'element list = nil | :: of 'element * 'element list
datatype 'a stream = Nil | Cons of 'a * (unit -> 'a stream);
An Infinite Sequence of An Infinite Sequence of IntegersIntegers
Chapter Eleven Modern Programming Languages 48
- fun intsfrom k = Cons(k,fn()=>intsfrom(k+1));val intsfrom = fn : int -> int stream- val nums = intsfrom 5;val nums = Cons (5,fn) : int stream- val Cons(head,_) = nums;val head = 5 : int- val Cons(_,f) = nums; val f = fn : unit -> int stream- val rest = f();val rest = Cons (6,fn) : int stream- val Cons(head,_) = rest;val head = 6 : int
Head and Tail for StreamsHead and Tail for Streams
Chapter Eleven Modern Programming Languages 49
fun head Nil = raise Empty| head (Cons(h,_)) = h;
fun thunk Nil = raise Empty| thunk (Cons(_,t)) = t;
fun force f = f ();
fun tail s = force (thunk s);(* Like the real list type, just gives the next Cons *)
Traversing the StreamTraversing the Stream
Chapter Eleven Modern Programming Languages 50
- nums;val it = Cons (5,fn) : int stream- head nums;val it = 5 : int- thunk nums;val it = fn : unit -> int stream- tail nums;val it = Cons (6,fn) : int stream- val rest = tail nums;val rest = Cons (6,fn) : int stream- head rest;val it = 6 : int- tail rest;val it = Cons (7,fn) : int stream
Other Stream FunctionsOther Stream Functions
Chapter Eleven Modern Programming Languages 51
fun next Nil = raise Empty| next c = head (tail c);
fun nth 0 s = head s| nth n s = nth (n-1) (tail s);
fun filter _ Nil = Nil| filter f (Cons (h,t)) = if (f h) then Cons (h, fn () => filter f (force t)) else filter f (force t);
fun map_ _ Nil = Nil| map_ f (Cons(h,t)) = Cons(f h, fn() => map_ f (force t));
Chapter Eleven Modern Programming Languages 52
- nums;val it = Cons (5,fn) : int stream- next nums;val it = 6 : int- nth 5 nums;val it = 10 : int- val evens = filter (fn x => x mod 2 = 0) nums;val evens = Cons (6,fn) : int stream- head evens;val it = 6 : int- next evens;val it = 8 : int- val iseven = map (fn x => x mod 2 = 0) nums;val iseven = Cons (false,fn) : bool stream- nth 0 iseven;val it = false : bool- nth 1 iseven;val it = true : bool
More ExamplesMore Examples
Chapter Eleven Modern Programming Languages 53
- val takeeven = filter (fn x => x mod 2 = 0);val takeeven = fn : int stream -> int stream- val evens = takeeven (intsfrom 1);val evens = Cons (2,fn) : int stream- printStrm 10 evens;2468101214161820
A A printStrmprintStrm Function for Function for intsints
Chapter Eleven Modern Programming Languages 54
fun printStrm _ Nil = ()| printStrm 0 _ = ()| printStrm n (Cons(x,rest)) = ( print(Int.toString x ^ "\n"); printStrm (n-1) (force rest) );
val printStrm = fn : int -> int stream -> unit
Obtaining Obtaining ““AllAll”” Prime Prime NumbersNumbers
Chapter Eleven Modern Programming Languages 55
- val primes = filter isPrime (intsfrom 2);val primes = Cons (2,fn) : int stream- strm2list 1000 primes;val it = [2,3,5,7,11,13,17,19,23,29,31,37,...] : int list- nth 1000 primes;val it = 7927 : int- nth 10000 primes;val it = 104743 : int-nth 100000 primes; val it = 1299721 : int (* took 1 second *)- nth 1000000 primes;val it = 15485867 : int (* took 21 seconds *)
Implementing Implementing foldlfoldlRemember foldl f c xs =
f(xn,f(xn-1,…,f(x2,f(x1,c))…))
fun foldl _ c nil = c
| foldl f c (x::xs) = foldl f (f (x,c)) xs;
Chapter Eleven Modern Programming Languages 56
foldl for Streamsfoldl for Streams
Chapter Eleven Modern Programming Languages 57
fun foldl_ _ c Nil = Cons(c, fn()=>Nil)| foldl_ f c (Cons(a,rest)) = let val v = f (a,c) in Cons(v, fn () => foldl_ f v (force rest)) end;
More ExamplesMore ExamplesComposing Even More StreamsComposing Even More Streams
Chapter Eleven Modern Programming Languages 58
-fun sum strm = foldl_ (op +) 0 strm;val sum = fn : int stream -> int stream- val addevens = sum (takeeven (intsfrom 1));val addevens = Cons (2,fn) : int stream- printStrm 10 addevens;2612203042567290110
Yet More!Yet More!
Chapter Eleven Modern Programming Languages 59
- fun drop _ Nil = Nil| drop 0 strm = strm| drop n (Cons(x,rest)) = drop (n-1) (force rest);val drop = fn : int -> 'a stream -> 'a stream- val less5 = drop 5 nums;val less5 = Cons (10,fn) : int stream- printStrm 5 less5;1011121314val it = () : unit- fun strm2list _ Nil = nil| strm2list 0 _ = nil| strm2list n (Cons(x,rest)) = x::(strm2list (n-1) (force rest));val strm2list = fn : int -> 'a stream -> 'a list- strm2list 5 less5;val it = [10,11,12,13,14] : int list
Even More ExamplesEven More ExamplesFrom MathematicsFrom Mathematics
See:◦iterate.sml◦newton.sml◦taylor.sml
Chapter Eleven Modern Programming Languages 60
Streams in PythonStreams in PythonUses generators
◦functions that can be resumed◦thereby producing a sequence of
values
See stream.py, iterate.py, newton.py
Chapter Eleven Modern Programming Languages 61