Map and Fold Building Powerful Abstractions. Hello. I’m Zach, one of Sorin’s students....

64
Map and Fold Building Powerful Abstractions

Transcript of Map and Fold Building Powerful Abstractions. Hello. I’m Zach, one of Sorin’s students....

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