640 likes | 757 Views
In this discourse, Zach, a student of Sorin, explores the evolution of programming concepts like Map, Fold, and Iteration. By examining high-level abstractions, he emphasizes the importance of elegant, efficient loops and the power of functional programming. Through concrete examples, including the doubling of integers and calculating string lengths, Zach illustrates the process of identifying common patterns, parameterizing incidental elements, and ultimately deriving elegant solutions. This journey aims to shift your perspective on conventional programming practices and inspire a deeper understanding of abstraction.
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) ... )