map and fold
DESCRIPTION
Map and Fold. Building Powerful Abstractions. Hello. I’m Zach, one of Sorin’s students. [email protected]. 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. - PowerPoint PPT PresentationTRANSCRIPT
Map and FoldBuilding Powerful
Abstractions
Hello.
I’m Zach, one of Sorin’s [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 ListCommon 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 function2. loop takes an accumulator argument3. 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