type synonyms We can give existing types new names. Syntax: type new type = ty
CSC324 — Functional Programming Typing, Exceptions in ML
new type becomes an alias (a synonym) for the existing type ty. -type float = real; type float = real
Afsaneh Fazly1
-type count = int and average = real; type count = int type average = real
Winter 2013
-val f : float = 2.3; val f = 2.3: float -val i = 3 : count; val i = 3: count
1
with many thanks to Anya Tafliovich, Gerald Penn, Sheila McIlraith, Wael Aboelsaddat, Tony Bonner, Eric Joanis, Suzanne Stevenson. 1
2
type synonyms
user-defined datatypes
But notice float, real, and average are all of the same base type, i.e., real:
General Syntax: datatype new_type = Cons1 of type1 | Cons2 of type2 ... | ConsN of typeN
-val f : float = 2.3; val f = 2.3 : float -val a = f : average; val a = 2.3 : average
• Defines a new type called new type.
-val sum = a+f; val sum = 4.6 : average
• type1,...,typeN are previously defined types.
• Cons1,...,ConsN are constructors. They are used to create
a value of the type new type.
-val sum = f+a; val sum = 4.6 : float
• of type is omitted if a constructor does not need any
argument (such constructors are called constants).
3
4
enumerated types
enumerated types
All constructors are constants (no argument), e.g.:
How would you implement this in Python?
-datatype color = Red | Blue | Green; datatype color = Blue | Green | Red -val c = Red; val c = Red : color -fun colorStr Red = "red" | colorStr Blue = "blue" | colorStr Green= "green"; val colorStr = fn : color -> string -colorStr c; val it = "red" : string 6
5
enumerated types
variant types
How would you implement this in Python?
Create union of different types:
class Enum(set): def __getattr__(self, name): if name in self: return name raise AttributeError
datatype number =
color = Enum(["Red", "Blue", "Green"]) animal = Enum(["Dog", "Cat"]) print color.Green, animal.Dog Note: a class in Python (Java) essentially defines a new data type.
7
8
variant types
variant types
Create union of different types: datatype number = R of real | I of int;
datatype number = R of real | I of int;
val lst = [R 2.2, I 3, I 4, R 0.1];
val n1 = I 2;
Write a function sumInts that takes a number list and returns the sum of the integers:
val n2 = R 3.0; val lst = [R 2.2, I 3, I 4, R 0.1]; (* val lst = [R 2.2,I 3,I 4,R 0.1] : number list *) Note: a variant type is a non-specific type, e.g., number may hold a real or an integer.
10
9
variant types
recursive types Recursive types are good for defining dynamic data structures, e.g., a linked list:
datatype number = R of real | I of int; val lst = [R 2.2, I 3, I 4, R 0.1]; Write a function sumInts that takes a number list and returns the sum of the integers: fun sumInts [] = 0 | sumInts ((I x)::rest) = x + sumInts rest | sumInts ((R x)::rest) = sumInts rest; sumInts : number list -> int; sumInts lst; (* val it = 7 : int *)
11
12
recursive types
recursive types
Recursive types are good for defining dynamic data structures, e.g., a linked list:
Recursive types are good for defining dynamic data structures, e.g., a linked list:
datatype llist = Nil | Node of int * llist;
datatype llist = Nil | Node of int * llist; (* constructing instances of the linked list *) val x = Nil; val y = Node(5,Nil); val z = Node(3, Node(2, Node(1,Nil)));
13
recursive types in Python
14
recursive types
class LinkedList: def __init__(): ’’’creates an initial linked list’’’ self.first = LinkedList.__Node()
datatype llist = Nil | Node of int * llist; val z = Node(3, Node(2, Node(1,Nil)));
def addNode(element): ...
Write a function len that takes a llist and returns its length.
class __Node: ’’’private node obj: element + pointer to next Node’’’ def __init__(self, element=None): self.element = element self.next = None def hasNext(self): ... def getNext(self): ... def setNext(self, nextNode): ... ... 15
16
recursive types
recursive types What about a polymorphic linked list?
datatype llist = Nil | Node of int * llist; val z = Node(3, Node(2, Node(1,Nil))); Write a function len that takes a llist and returns its length. (* length of a linked list *) fun len Nil = 0 | len (Node (_,xs)) = 1 + len xs; len : llist -> int len z; val it = 3 : int
18
17
recursive types
recursive types
What about a polymorphic linked list?
What about a polymorphic linked list?
• Use a type variable.
• Use a type variable.
Remember type variables: ’a ⇒ any type ’’a ⇒ any type for which equality is defined
Remember type variables: ’a ⇒ any type ’’a ⇒ any type for which equality is defined
datatype ’a llist = Nil | Node of ’a * (’a llist);
18
19
recursive types
recursive types
A polymorphic linked list: datatype ’a llist = Nil | Node of ’a * (’a llist);
datatype ’a llist = Nil | Node of ’a * (’a llist); val y = Node(5,Nil);
fun len Nil = 0 | len (Node (_,xs)) = 1 + len xs; len : ’a llist -> int
(* int llist *)
val z = Node("A", Node("B",Nil));
(* string llist *)
len y; (* val it = 1 : int *) len z; (* val it = 2 : int *)
21
20
recursive types
recursive types
Example: a polymorphic binary tree.
Example: a polymorphic binary tree. datatype ’a tree = Leaf of ’a | Node of ’a * ’a tree * ’a tree;
22
23
recursive types
recursive types
Example: a polymorphic binary tree.
Example: a polymorphic binary tree.
datatype ’a tree = Leaf of ’a | Node of ’a * ’a tree * ’a tree;
datatype ’a tree = Leaf of ’a | Node of ’a * ’a tree * ’a tree;
Function for summing-up all values in an int tree:
Function for summing-up all values in an int tree: fun sumT (Leaf x) = x | sumT (Node(x,ltree,rtree)) = x + sumT(ltree) + sumT(rtree);
25
24
recursive types
recursive types
Example: Tree representation of simple mathematical expressions.
datatype math_tree = Leaf of int | Unary of (int -> int) * math_tree | Binary of (int * int -> int) * math_tree * math_tree
(|-3| + 2) + ((-1) + 4) * 7)
add add
mult
abs neg 3
2 neg
add
7 4
1
What is the datatype we need? 26
27
recursive types
recursive types The tree in the figure:
datatype math_tree = Leaf of int | Unary of (int -> int) * math_tree | Binary of (int * int -> int) * math_tree * math_tree
val t = Binary(op +, Binary(op +, Unary((fn x => if x > 0 then x else ~x), Unary (op ~, Leaf 3)), Leaf 2), Binary(op *, Binary(op +, Unary(op ~, Leaf 1), Leaf 4), Leaf 7))
Instances of type math tree: Leaf 3; Unary(op ~, Leaf 3); Binary(op +, Leaf 4, Unary(op ~, Leaf 3));
28
29
recursive types
recursive types
Define a function eval: math tree -> int that returns the result of evaluatng a math tree:
Define a function eval: math tree -> int that returns the result of evaluatng a math tree: fun eval (Leaf n) = n | eval (Unary (f,t)) = f (eval t) | eval (Binary (f,l,r)) = f (eval l,eval r); eval : math_tree -> int - eval t; val it = 26 : int
30
31
recursive types in Python/Java
recursive types in Python/Java
How would you define the datatype math tree and the function eval in Python or Java?
How would you define the datatype math tree and the function eval in Python or Java?
What differences do you see between ML and Python/Java?
32
32
mutual recursion in ML
mutual recursion in ML
Let’s mimic the Scheme definitions of even and odd:
Use the keyword and.
fun even 0 = true | even x = odd (x - 1);
fun | and |
fun odd 0 = false | odd x = even (x - 1); Error:
unbound variable or constructor:
even 0 = true even x = odd (x - 1) odd 0 = false odd x = even (x - 1);
even : int -> bool; odd : int -> bool
odd
even 42; (* val it = true : bool *) odd 42; (* val it = false : bool *)
33
34
mutually recursive types
mutually recursive types
Example: a binary tree with labeled branches:
Example: a binary tree with labeled branches:
6
1
7
2
8
7
2
3
4
6
1
8
3
4
5
5
datatype ’a tree = Empty | Node of ’a branch * ’a branch and ’a branch = Branch of ’a * ’a tree; 36
35
mutually recursive types
mutually recursive types The tree in the figure:
datatype ’a tree = Empty | Node of ’a branch * ’a branch and ’a branch = Branch of ’a * ’a tree;
val lt = Node(Branch(1, Node(Branch(2, Empty), Branch(3, Node(Branch(4, Empty), Branch(5, Empty))))), Branch(6, Node(Branch(7, Empty), Branch(8, Empty))));
Instances of tree: Empty; Node(Branch(7,Empty), Branch(8,Empty)); Node(Branch(1,Empty), Branch(6, Node(Branch(7,Empty), Branch(8,Empty)))); 37
38
mutually recursive types
mutually recursive types
datatype ’a tree = Empty | Node of ’a branch * ’a branch and ’a branch = Branch of ’a * ’a tree
datatype ’a tree = Empty | Node of ’a branch * ’a branch and ’a branch = Branch of ’a * ’a tree
Define listTree that returns the list of branch labels, in order:
Define listTree that returns the list of branch labels, in order: fun listTree Empty = [] | listTree (Node (l,r)) = (listBranch l) @ (listBranch r) and listBranch (Branch (b,t)) = b :: (listTree t); listTree : ’a tree -> ’a list; listBranch : ’a branch -> ’a list listTree t; (* val it = [1,2,3,4,5,6,7,8] : int list *)
39
recursive types 1. A powerful tool for constructing new types. 2. The structure of the datatype suggests the structure of the recursive function on the datatype ⇒ structural recursion.
41
40