52
CSE-321 Programming Languages Introduction to Functional Programming (Part II) POSTECH March 13, 2006 박박박

CSE-321 Programming Languages Introduction to Functional Programming (Part II) POSTECH March 13, 2006 박성우

Embed Size (px)

Citation preview

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.

4

f : bool -> ?

fn f => (f true, f false) : (bool -> ?) -> ? * ?

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

16

Mathematics vs. Computer Science

• CS ½ Math? • CS Math?

Math

CS

Math

CS

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

37

Higher-order Functions• Take functions as arguments.• Return functions as the result.

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;

52

So it is YOU who will grade your homework!