640 likes | 751 Views
Map and Fold. Building Powerful Abstractions. Hello. I’m Zach, one of Sorin’s students. ztatlock@cs.ucsd.edu. 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.
E N D
Map and Fold Building Powerful Abstractions
Hello. I’m Zach, one of Sorin’s students. ztatlock@cs.ucsd.edu
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 A language that doesn't affect the way you think about programming is not worth knowing. Alan Jay Perlis
Evolution of Iteration • for(x in a) { • print x * 2 • } • for(i=0; i<n; i++) { • print a[i] * 2 • } Abstract • i = 0; • while(i < n) { • print a[i] * 2 • i++ • } i = 0 label L0 if(i >= n) goto L1 print a[i] * 2 i++ goto L0 label L1 Ugly Elegant
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 Map Fold 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_intsxs = match xs with | [] –> [] | x::ys–> double_intx :: double_intsys
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_lensxs = match xs with | [] –> [] | x::ys–> str_len x :: str_lensys
Map : Find the Pattern let rec double_intsxs = match xs with | [] –> [] | x::ys–> double_int x :: double_intsys let rec str_lensxs = match xs with | [] –> [] | x::ys–> str_len x :: str_lensys
Map : Find the Pattern let rec double_intsxs = match xs with | [] –> [] | x::ys–> double_int x :: double_intsys Base function let rec str_lensxs = match xs with | [] –> [] | x::ys–> str_len x :: str_lensys
Map : Find the Pattern let rec double_intsxs = match xs with | [] –> [] | x::ys–> double_int x :: double_intsys Base function Apply to head let rec str_lensxs = match xs with | [] –> [] | x::ys–> str_len x :: str_lensys
Map : Find the Pattern let rec double_intsxs = match xs with | [] –> [] | x::ys–> double_int x :: double_intsys Base function Apply to head Recurse let rec str_lensxs = match xs with | [] –> [] | x::ys–> str_len x :: str_lensys
Map : Derive from the Pattern Base function Apply to head Recurse
Map : Derive from the Pattern let rec map f xs = match xs with | [] –> [] | x::ys-> f x :: map f ys Base function Apply to head Recurse
Map : Derive from the Pattern let rec map f xs = match xs with | [] –> [] | x::ys-> f x :: map f ys Base function Apply to head Recurse
Key Idea: Take a function as a parameter! Map : Derive from the Pattern let rec map f xs = match xs with | [] –> [] | x::ys-> f x :: map f ys Base function Apply to head Recurse
Map : Derive from the Pattern let rec map f xs = match xs with | [] –> [] | x::ys-> f x :: map f ys Base function Apply to head Recurse
Map : Derive from the Pattern let rec map f xs = match xs with | [] –> [] | x::ys-> f x :: map f ys Base function Apply to head Recurse
Application: Print an int list Assume function print_int Use mapto print a list of ints
Application: Print an int list Assume function print_int Use mapto 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_intsxs = match xs with | [] -> [] | x::ys-> print_int x :: print_intsys
Map Summary Map takes: a -> b and 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 • map print (map double a) • for(x in a) { • print x * 2 • } • for(i=0; i<n; i++) { • print a[i] * 2 • } Abstract • i = 0; • while(i < n) { • print a[i] * 2 • i++ • } i = 0 label L0 if(i >= n) goto L1 print a[i] * 2 i++ goto L0 label L1 Ugly Elegant
Building Iteration Abstractions Map Fold 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_intsxs = match xs with | [] -> 0 | x::ys-> add x (add_intsys)
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_strsxs = match xs with | [] -> “” | x::ys-> cat x (cat_strsys)
Fold : Find the Pattern let rec add_intsxs = match xs with | [] –> 0 | x::ys–> add x (add_intsys) let rec cat_strsxs = match xs with | [] –> “” | x::ys–> cat x (cat_strsys)
Fold : Find the Pattern 1. Base Val b let rec add_intsxs = match xs with | [] –> 0 | x::ys–> add x (add_intsys) let rec cat_strsxs = match xs with | [] –> “” | x::ys–> cat x (cat_strsys)
Fold : Find the Pattern 1. Base Val b 2. Base Fun f let rec add_intsxs = match xs with | [] –> 0 | x::ys–> add x (add_intsys) let rec cat_strsxs = match xs with | [] –> “” | x::ys–> cat x (cat_strsys)
Fold : Find the Pattern 1. Base Val b 2. Base Fun f 3. End on b let rec add_intsxs = match xs with | [] –> 0 | x::ys–> add x (add_intsys) let rec cat_strsxs = match xs with | [] –> “” | x::ys–> cat x (cat_strsys)
Fold : Find 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 add_intsxs = match xs with | [] –> 0 | x::ys–> add x (add_intsys) let rec cat_strsxs = match xs with | [] –> “” | x::ys–> cat x (cat_strsys)
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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys 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 recfold f xs b = match xs with | [] –> b | x::ys–> fx (fold fys b)
Application: Multiply int list Assume function mul = (*) Use foldto take product of a list of ints
Application: Multiply int list Assume function mul = (*) Use foldto take product of a list of ints let product xs = fold (*) xs 1
Compare: Using Foldvs. Not let product xs = fold (*) xs 1 vs. let recproduct 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 paramsto 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) ... )