map and fold building powerful abstractions. hello. i’m zach, one of sorin’s students....

64
Map and Fold Building Powerful Abstractions

Upload: clement-lucas

Post on 18-Dec-2015

213 views

Category:

Documents


0 download

TRANSCRIPT

Map and FoldBuilding Powerful

Abstractions

Hello.

I’m Zach, one of Sorin’s students.

[email protected]

A language that doesn't affect the way you think about programming is not worth knowing.

Alan Jay Perlis

If you manage to survive a shipwreck by clinging to a piano top, well, that doesn’t mean the best way to design a life preserver is as a piano top.

I think we are clinging to a great many piano tops.

Buckminster Fuller

Evolution of Iteration

Evolution of Iteration

i = 0label L0if(i >= n) goto L1print a[i] * 2i++goto L0label L1

i = 0;while(i < n) { print a[i] * 2 i++}

for(x in a) { print x * 2}

for(i=0; i<n; i++) { print a[i] * 2}

Ugly Elegant

Abst

ract

Building Iteration Abstractions

Roll our own abstractions w/ higher order funcs

Step 1: Identify common patterns

Step 2: Retain the fundamental and Parameterize away the incidental

Building Iteration Abstractions

1. Map

2. Fold

3. Tail Recursion

A good loop is fast, safe, and elegant.

Map : Apply Func Over List

Common Task:do something to every item in a list

map f [x1; x2; ...; xN]=

[f x1; f x2; ...; f xN]

But how do we implement it?

Derive by abstracting from particular instances

Instance: Double an int list

Assume function double_int = (*) 2

Write function to double a list of ints

Instance: Double an int list

Assume function double_int = (*) 2

Write function to double a list of ints

let rec double_ints xs = match xs with | [] –> [] | x::ys –> double_int x :: double_ints ys

Instance: Lengths from a string list

Assume function str_len

Write function for lengths of strings in a list

Instance: Lengths from a string list

Assume function str_len

Write function for lengths of strings in a list

let rec str_lens xs = match xs with | [] –> [] | x::ys –> str_len x :: str_lens ys

Map : Find the Pattern

let rec double_ints xs = match xs with | [] –> [] | x::ys –> double_int x :: double_ints ys

let rec str_lens xs = match xs with | [] –> [] | x::ys –> str_len x :: str_lens ys

Map : Find the Pattern

let rec double_ints xs = match xs with | [] –> [] | x::ys –> double_int x :: double_ints ys

let rec str_lens xs = match xs with | [] –> [] | x::ys –> str_len x :: str_lens ys

1. Base function

Map : Find the Pattern

let rec double_ints xs = match xs with | [] –> [] | x::ys –> double_int x :: double_ints ys

let rec str_lens xs = match xs with | [] –> [] | x::ys –> str_len x :: str_lens ys

1. Base function

2. Apply to head

Map : Find the Pattern

let rec double_ints xs = match xs with | [] –> [] | x::ys –> double_int x :: double_ints ys

let rec str_lens xs = match xs with | [] –> [] | x::ys –> str_len x :: str_lens ys

1. Base function

2. Apply to head

3. Recurse

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

let rec map f xs = match xs with | [] –> [] | x::ys -> f x :: map f ys

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

let rec map f xs = match xs with | [] –> [] | x::ys -> f x :: map f ys

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

let rec map f xs = match xs with | [] –> [] | x::ys -> f x :: map f ys

Key Idea:Take a function as a parameter!

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

let rec map f xs = match xs with | [] –> [] | x::ys -> f x :: map f ys

Map : Derive from the Pattern

1. Base function

2. Apply to head

3. Recurse

let rec map f xs = match xs with | [] –> [] | x::ys -> f x :: map f ys

Application: Print an int list

Assume function print_int

Use map to print a list of ints

Application: Print an int list

Assume function print_int

Use map to print a list of ints

let print_ints = map print_int

Compare: Using Map vs. Not

let print_ints = map print_int

vs.

let rec print_ints xs = match xs with | [] -> [] | x::ys -> print_int x :: print_ints ys

Map Summary

Map takes: a -> band provides: a list -> b list

Which corresponds to the common task:do something to every item in a list

map f [x1; x2; ...; xN]=

[f x1; f x2; ...; f xN]

Evolution of Iteration

i = 0label L0if(i >= n) goto L1print a[i] * 2i++goto L0label L1

i = 0;while(i < n) { print a[i] * 2 i++}

for(i=0; i<n; i++) { print a[i] * 2}

Ugly Elegant

Abst

ract

map print (map double a)

for(x in a) { print x * 2}

Building Iteration Abstractions

1. Map

2. Fold

3. Tail Recursion

A good loop is fast, safe, and elegant.

Fold : Crunch Down a List

Common Task:crunch a list of values down to a single value

fold f [x1; x2; ...; xN] base=

(f x1 (f x2 ... (f xN base) ... )

But how do we implement it?

Derive by abstracting from particular instances

Instance: Add up an int list

Assume function add = (+)

Write function to add up a list of ints

Instance: Add up an int list

Assume function add = (+)

Write function to add up a list of ints

let rec add_ints xs = match xs with | [] -> 0 | x::ys -> add x (add_ints ys)

Instance: Concat together string list

Assume function cat = (^)

Write function to concat a list of strings

Instance: Concat together string list

Assume function cat = (^)

Write function to concat a list of strings

let rec cat_strs xs = match xs with | [] -> “” | x::ys -> cat x (cat_strs ys)

Fold : Find the Pattern

let rec add_ints xs = match xs with | [] –> 0 | x::ys –> add x (add_ints ys)

let rec cat_strs xs = match xs with | [] –> “” | x::ys –> cat x (cat_strs ys)

Fold : Find the Pattern

let rec add_ints xs = match xs with | [] –> 0 | x::ys –> add x (add_ints ys)

let rec cat_strs xs = match xs with | [] –> “” | x::ys –> cat x (cat_strs ys)

1. Base Val b

Fold : Find the Pattern

let rec add_ints xs = match xs with | [] –> 0 | x::ys –> add x (add_ints ys)

let rec cat_strs xs = match xs with | [] –> “” | x::ys –> cat x (cat_strs ys)

1. Base Val b

2. Base Fun f

Fold : Find the Pattern

let rec add_ints xs = match xs with | [] –> 0 | x::ys –> add x (add_ints ys)

let rec cat_strs xs = match xs with | [] –> “” | x::ys –> cat x (cat_strs ys)

1. Base Val b

2. Base Fun f

3. End on b

Fold : Find the Pattern

let rec add_ints xs = match xs with | [] –> 0 | x::ys –> add x (add_ints ys)

let rec cat_strs xs = match xs with | [] –> “” | x::ys –> cat x (cat_strs ys)

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Key Idea:Take a function as a parameter!

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Fold : Derive from the Pattern

1. Base Val b

2. Base Fun f

3. End on b

4. Apply f to head and val from rest

let rec fold f xs b = match xs with | [] –> b | x::ys –> f x (fold f ys b)

Application: Multiply int list

Assume function mul = (*)

Use fold to take product of a list of ints

Application: Multiply int list

Assume function mul = (*)

Use fold to take product of a list of ints

let product xs =fold (*) xs 1

Compare: Using Fold vs. Not

let product xs = fold (*) xs 1

vs.

let rec product xs = match xs with | [] -> 1 | x::ys -> x * (product ys)

Fold Summary

Fold turns: x1 :: x2 :: ... :: []

into: x1 op x2 op ... op base

where op and base are the params to fold.

Which corresponds to the common task:crunch a list of values down to a single value

fold f [x1; x2; ...; xN] base=

(f x1 (f x2 ... (f xN base) ... )

Building Iteration Abstractions

1. Map

2. Fold

3. Tail Recursion

A good loop is fast, safe, and elegant.

Tail Recursion

Special type of functioncompiler can easily optimize into a loop

More efficient than naïve recursionuses less time and stack space

Require all returns to be eitherA: a valueB: call to the same function

Tail Recursion

Is this function tail recursive?

let rec is_even x = match x with | 0 -> true | 1 -> false | _ -> is_even (x – 2)

Yes.

Tail Recursion

Is this function tail recursive?

let rec factorial x = match x with | 0 -> 1 | _ -> x * (factorial (x – 1))

No.

not a call to factorial

Tail Recursion

Can we make factorial tail recursive?

Tail Recursion

Can we make factorial tail recursive?

let factorial x =let rec loop acc x =

match x with | 0 -> acc | _ -> loop (x * acc) (x – 1) in loop 1 x

Yes.

Tail Recursion

Is this function tail recursive?

let rec range a b = if a > b then [] else a :: range (a + 1) b

No.

not a call to range

Tail Recursion

Can we make range tail recursive?

Tail Recursion

Can we make range tail recursive?

let range a b =let rec loop acc a b =

if a > b then acc else loop (b::acc) a (b – 1) in loop [] a b

Yes.

Tail Recursion : What’s the Pattern?

Not a generic recipe like Map and Fold!

Roughly :

1. write a “loop” helper function

2. loop takes an accumulator argument

3. base case returns the accumulator

4. recursive case calls loop w/ updated

acc

Putting the Pieces Together

Use functions from today to write factorial.

let factorial n =

Putting the Pieces Together

Use functions from today to write factorial.

let factorial n = fold (*) (range 1 n) 1

A Final Thought . . .

It’s abstractions

all the way down!

abstraction