cse-321 programming languages introduction to functional programming (part ii) postech march 13,...
TRANSCRIPT
CSE-321 Programming Languages
Introduction to Functional Programming(Part II)
POSTECH
March 13, 2006
박성우
2
Outline• Expressions and values V• Variables V• Functions V• Types
– Polymorphism• Recursion• Datatypes• Pattern matching• Higher-order functions• Exceptions• Modules
3
What is the Type of ?
true,
false)
(
fn f => (f true, f false)
f
f
f
All we know about f is that it takes booleans as arguments.
5
f : bool -> 'a
fn f => (f true, f false) : (bool -> 'a) -> 'a * 'a
• 'a– type variable– usually read as alpha– means 'for any type alpha'
6
Polymorphic Types• Types involving type variables 'a, 'b, 'c, ...• E.g.
– fn x => x : 'a -> 'a
– fn x => fn y => (x, y) : 'a -> 'b -> ('a * 'b)
– fn (x : 'a) => fn (y : 'a) => x = y :'a -> 'a -> bool(* actually does not typecheck! *)
7
Equality Types• Motivation
– Equality (=) is not defined on every type.– E.g.
• comparing two functions for equality?
• Type variables with equality– ''a, ''b, ''c, ...– ''a means 'for any type alpha
for which equality is defined'
– fn (x : ''a) => fn (y : ''a) => x = y :''a -> ''a -> bool
8
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion• Datatypes• Pattern matching• Higher-order functions• Exceptions• Modules
9
Recursion vs. Iteration• Recursion in SML
fun sum n =if n = 0 then 0else sum (n - 1) + n
• Iteration in C
int i, sum;for (i = 0, sum = 0;
i <= n; i++)
sum += n;
• Recursion is not an awkward toolif you are used to functional programming.
• Recursion seems elegant but inefficient!
10
Recursion in Actionfun sum n =
if n = 0 then 0else sum (n - 1) + n
call stack
evaluation
f 10
f 8
f 9
...
f 1
f 0
55
36 + 9
45 + 10
...0 + 1
1 + 2
0
further computation
11
Funny Recursionfun zero n =
if n = 0 then 0else zero (n - 1)
call stack
evaluation
f 10
f 9
f 8
...
f 1
f 0
0
0
0
0
0
...0
no further computation
12
Funny Recursion Optimizedfun zero n =
if n = 0 then 0else zero (n - 1)
call stack
evaluation
f 10
f 9
f 8
...
f 1
f 0
0
0
0
0
0...
0
13
Funny Recursion Further Optimized
fun zero n =if n = 0 then 0else zero (n - 1)
call stack
evaluation
f 10 f 9 f 8 ...
f 1 f 0 0
14
Tail Recursive Function• A tail recursive function f:
– A recursive call to f is the last step in evaluating the function body.
– That is, no more computation remains after calling f itself.
• A tail recursive call needs no stack!• A tail recursive call is as efficient as iteration!
15
Example• Tail recursive sum
fun sum' accum k =if k = 0 then accumelse sum' (accum + k) (k - 1)
fun sum n = sum' 0 n
• Non-tail recursive sum
fun sum n =if n = 0 then 0else sum (n - 1) + n
• Think about the invariant of sum:– given:
sum' accum k– invariant:
accum = (k + 1) + ... + n
17
Factorial Function fac 1 = 1 fac n = n * fac (n - 1)
• Makes sense in– Math– CS
fac 1 = 1 fac n = fac (n + 1) / n
• Makes sense in math.• But not in CS:
– it always diverges.
• "Then what kind of recursive functions are computationally meaningful?"
) domain theory in computer science• Other examples
– real numbers vs. computable real numbers– logic in math vs. logic in computer science
18
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion V• Datatypes• Pattern matching• Higher-order functions• Exceptions• Modules
19
Enumeration Types in Cenum shape { Circle, Rectangle, Triangle};
• Great flexibility– e.g.
Circle + 1 == RectangleTriangle - 1 == Rectangle(Circle + Triangle) / 2 == Rectangle
• But is this good or bad?
20
Datatypes in SMLdatatype shape = Circle | Rectangle | Triangle
• No flexibility– e.g.
Circle + 1 (x)Triangle - 1 (x)Circle + Triangle (x)
• But high safety.
21
Primitive Setdatatype set =
Empty | Singleton | Pair |Many
- Empty;val it = Empty : set- Many;val it = Many : set
22
Primitive Set with Argumentsdatatype set =
Empty | Singleton | Pair |Many of int
- Many 5;val it = Many 5 : set
23
Primitive Set with Type Parameters
datatype 'a set = Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
- Singleton 0;val it = Singleton 0 : int set- Pair (0, 1);val it = Pair (0, 1) : int set
24
Primitive Set with Type Parameters
datatype 'a set = Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
- Pair (Singleton 0, Pair (0, 1))val it = Pair (Singleton 0, Pair (0, 1)) :
int set set
25
Primitive Set with Type Parameters
datatype 'a set = Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
- Empty;val it = Empty : 'a set- Many 5;val it = Many 5 : 'a set
26
Primitive Set with Type Parametersdatatype 'a set =
Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
- Pair (0, true);stdIn:27.1-27.15 Error: operator and operand
don't agree [literal] operator domain: int * int operand: int * bool in expression: Pair (0,true)
27
Recursive Set with Type Parameters
datatype 'a set = Empty | NonEmpty of 'a * 'a set
• This is essentially the definition of datatype list.
28
Datatype listdatatype 'a list =
nil | :: of 'a * 'a list
- nil;val it = [] : 'a list- 2 :: nil;val it = [2] : int list- 1 :: (2 :: nil);val it = [1,2] : int list- 1 :: 2 :: nil;val it = [1,2] : int list
29
Datatype listdatatype 'a list =
nil | :: of 'a * 'a list
- 1 :: [2] :: nil;- [1] :: 2 :: nil;- [1] :: [2] :: nil;val it = [[1],[2]] : int list list- [1] :: [[2]];val it = [[1],[2]] : int list list
(X)(X)
30
Using Datatypes• We know how to create values of various datatypes:
– shape– set– int set– int list– ...
• But how do we use them in programming?• What is the point of creating datatype values that
are never used?
31
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion V• Datatypes V• Pattern matching• Higher-order functions• Exceptions• Modules
32
Simple Patterndatatype shape = Circle | Rectangle |
Triangle
(* convertToEnum : shape -> int *)fun convertToEnum (x : shape) : int =
case x ofCircle => 0
| Rectangle => 1| Triangle => 2
33
Pattern with Argumentsdatatype 'a set =
Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
fun size (x : 'a set) : int =case x of
Empty => 0| Singleton e => 1| Pair (e1, e2) => 2| Many n => n
34
Wildcard Pattern _ : "don't care"datatype 'a set =
Empty | Singleton of 'a | Pair of 'a * 'a |Many of int
fun isEmpty (x : 'a set) : bool =case x ofEmpty => true
| _ => false
35
Pattern with Type Annotationdatatype 'a list =
nil | :: of 'a * 'a list
fun length (x : 'a list) : int =case x of
(nil : 'a list) => 0| (_ : 'a) :: (tail : 'a list) =>
1 + length tail
36
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion V• Datatypes V• Pattern matching V• Higher-order functions• Exceptions• Modules
38
Why "Higher-order"?• T0 ::= int | bool | real | unit | ...
• T1 ::= T0 -> T0 | T0 (* 1st order *)
• T2 ::= T1 -> T1 | T1 (* 2nd order *)
• T3 ::= T2 -> T2 | T 2 (* higher order *)
• ...
39
Higher-order Functions in List• val exists : ('a -> bool) -> 'a list -> bool• val all : ('a -> bool) -> 'a list -> bool• val map : ('a -> 'b) -> 'a list -> 'b list• val filter : ('a -> bool) -> 'a list -> 'a list• val app : ('a -> unit) -> 'a list -> unit
(* printInt : int -> unit *)fun printInt i = TextIO.print ((Int.toString i) ^ "\n" );List.app printInt [1, 2, 3];
40
List Fold Function• foldl : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
foldr : ('a * 'b -> 'b) -> 'b -> 'a list -> 'b
• foldl f b0 [a0, a1, a2, ..., an-1]
b0
a0
f b1
a1
f b2
an-1
f bn
a2
f b3 bn-2
an-2
f bn-1...
...
41
ExamplesList.exists f l =
List.foldl (fn (a, b) => b orelse f a) false lList.all f l =
List.foldl (fn (a, b) => b andalso f a) true lList.app f l =
List.foldl (fn (a, _) => f a) () l List.map f l =
List.foldr (fn (a, b) => f a :: b) nil lList.filter f l =
List.foldr (fn (a, b) => if f a then a :: b else b) nil l
42
More Examplesfun sum (l : int list) =
List.foldl (fn (a, accum) => a + accum) 0 l
fun reverse (l : 'a list) =List.foldl (fn (a, rev) => a :: rev) nil l
• Whenever you need iterations over lists,first consider foldl and
foldr.
43
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion V• Datatypes V• Pattern matching V• Higher-order functions V• Exceptions
– exception: please see the course notes.• Modules
44
Outline• Expressions and values V• Variables V• Functions V• Types V• Recursion V• Datatypes V• Pattern matching V• Higher-order functions V• Exceptions V• Modules
45
Structures and Signatures• Structure
– collection of type declarations, exceptions, values, and so on.
structure Set =struct
type 'a set = 'a listval emptySet = nilfun singleton x = [x]fun union s1 s2 = s1 @ s2
end
• Signature– conceptually type of
structures.
signature SET =sig
type 'a setval emptySet : 'a setval singleton : 'a -> 'a setval union : 'a set -> 'a set -> 'a set
end
46
Structures + Signatures• Transparent constraint
– Type definition is exported to the outside.
structure Set : SET =struct
type 'a set = 'a listval emptySet = nilfun singleton x = [x]fun union s1 s2 = s1 @ s2
end
- Set.singleton 1 = [1];val it = true : bool
• Opaque constraint– No type definition is
exported.
structure Set :> SET =struct
type 'a set = 'a listval emptySet = nilfun singleton x = [x]fun union s1 s2 = s1 @ s2
end
- Set.singleton 1 = [1];(* Error! *)
47
I need to test your 57 structures!structure BetOne :> HW_ONE = ...structure Bigh2000One :> HW_ONE = ...structure BoongOne :> HW_ONE = structure BrandonOne :> HW_ONE = ......structure ZiedrichOne :> HW_ONE = ...
• How can I test 57 structures?– They all conform to the same signature.
48
Simple (but Ugly) Solutionfun sumTest f = f nil = 0 andalso f [1, 2, 3] = 6fun facTest f = f 1 = 1 andalso f 3 = 6 andalso f 7 = 5040...
fun allTest (sum, fac, ...) = let
val sumScore = if sumTest sum then 10 else 0val facScore = if facTest fac then 4 else 0...
insumScore + facScore + ...
end
allTest (BetOne.sum, BetOne.fac, ...);allTest (Bigh2000One.sum, Bigh2000One.fac, ...);allTest (BoongOne.sum, BoongOne.fac, ...);allTest (BrandonOne.sum, BrandonOne.fac, ...);...allTest (ZiedrichOne.sum, ZiedrichOne.fac, ...);
49
Functors• Functions on structures
– takes a structure as an argument– returns a structure as the result
structure
structure
50
HW1 Test Functorsignature HW_TEST =sig
val score : intend
functor Hw1TestFn (P : HW_ONE) : HW_TEST =struct
structure S = Hw1Solution val sumScore =
if P.sum nil = S.sum nil andalso P.sum [1, 2, 3] = S.sum [1, 2, 3] then 10 else 0
val facScore = if P.fac 1 = S.fac 1 andalso P.fac 3 = S.fac 3 andalso
P.fac 7 = S.fac 7 then 4 else 0
...val score = sumScore + facScore + ...
end
51
HW1 Test Functor in Actionstructure BetOneTest = Hw1TestFn (BetOne)structure Bigh2000OneTest = Hw1TestFn
(Bigh2000One)structure BoongOneTest = Hw1TestFn (BoongOne)structure BrandonOneTest = Hw1TestFn
(BrandonOne)...structure ZiedrichOneTest = Hw1TestFn (ZiedrichOne)
BetOneTest.score;Bigh2000OneTest.score;BoongOneTest.score;BrandonOneTest.score;...ZiedrichOneTest.score;