Download presentation
Presentation is loading. Please wait.
1
Abstracting Repetitions
Fold Operations Abstracting Repetitions cs7120(Prasad) L6-FOLD
2
Motivation : Appending lists
lappend (link) generalization of binary append to appending an arbitrary number of lists fun lappend [] = [] | lappend (s::ss) = (lappend ss) lappend : ’a list list -> ’a list cs7120(Prasad) L6-FOLD
3
Properties (Identities)
(map f) o lappend = lappend o (map (map f)) filter p ys) = (filter p (filter p ys) (filter p) o lappend = lappend o (map (filter p)) Efficiency issues and transformations; cf. associative, commutative and distributive laws; Mathematical foundation for code optimization cs7120(Prasad) L6-FOLD
4
Fold Operators Generalize binary operators to n-ary functions (list functions). Abstract specific patterns of recursion / looping constructs. Potential for optimization of special forms. foldl, accumulate, revfold, … foldr, reduce, fold, … foldl1 foldr1 Operator vs infix function vs function cs7120(Prasad) L6-FOLD
5
Foldr (SML97) foldr f a [x1,x2,…,xn] = f( x1 , f(x2, …, f(xn,a)...))
fun foldr f a [] = a | foldr f a (x::xs) = f (x, foldr f a xs) foldr : (’a*’b -> ’b) ->’b -> ’a list -> ’b foldr (op +) 10 [1,2,3] = 16 Normally, f is associative and a is identity wrt f. foldr (op +) a [x1,x2,x3] = ( x1 + ( x2 + ( x3 + a) ) ) ) foldr (op ::) [1,0] [4,3,2] = [4,3,2,1,0] cs7120(Prasad) L6-FOLD
6
Examples foldr (op +) a [x1,x2,x3] = ( x1 + ( x2 + ( x3 + a) ) ) )
[4,3,2,1,0] cs7120(Prasad) L6-FOLD
7
(cont’d) fold in OldML (not suited for partial eval.)
fold : (’a*’b -> ’b) -> ’a list ->’b -> ’b foldr in Bird and Wadler (Curried func.) reduce in Reade foldr : (’a -> ’b -> ’b) -> ’b -> ’a list -> ’b cs7120(Prasad) L6-FOLD
8
Foldl (SML97) foldl f a [x1,x2,…,xn] = f(xn,f(…,f(x2,f(x1,a))…))
fun foldl f a [] = a | foldl f a (x::xs) = foldl f (f(x,a)) xs foldl : (’a*’b -> ’b) ->’b -> ’a list -> ’b foldl (op * ) 10 [1,2,3] = 60 Normally, f is associative and a is identity wrt f. foldl (op *) [x1,x2,…,xn] a = (xn * (…*(x2 * (x1 * a))...)) foldl (op ::) [1,0] [4,3,2] = [2,3,4,1,0] foldl [0] [[1],[2],[3],[4]] = [4,3,2,1,0] fun foldl f a [] = a | foldl f a (x::xs) = foldl f (f(a,x)) xs foldl : (‘b*‘a -> ‘b) ->‘b -> ‘a list -> ‘b cs7120(Prasad) L6-FOLD
9
foldl (op @) [0] [[1],[2],[3],[4]]
Examples foldl (op *) a [x1,x2,…,xn] = (xn * (…*(x2 * (x1 * a))...)) foldl [0] [[1],[2],[3],[4]] [4,3,2,1,0] foldl (op ::) [1,0] [4,3,2] [2,3,4,1,0] cs7120(Prasad) L6-FOLD
10
(cont’d) revfold in OldML (not suited for partial eval.)
revfold : (’b*’a -> ’b) -> ’a list ->’b -> ’b foldl in Bird and Wadler (Curried func.) accumulate in Reade foldl : (’b -> ’a -> ’b) -> ’b -> ’a list ->’b cs7120(Prasad) L6-FOLD
11
Examples fun pack ds = foldl (fn (d,v)=> d+v*10) 0 ds
fun packNot ds = foldl (fn (d,v)=> d*10+v) 0 ds packNot [1,2,3,4] = 100 fun packNott ds = foldr (fn (d,v)=> d+v*10) 0 ds packNott [1,2,3,4] = 4321 Horner’s rule cs7120(Prasad) L6-FOLD
12
foldr (fn (x,xs) => x::xs) [] lis myId [1,2,3,4] = [1,2,3,4]
fun myId lis = foldr (fn (x,xs) => x::xs) [] lis myId [1,2,3,4] = [1,2,3,4] fun myRev lis = foldl (fn (x,xs) => x::xs) [] lis myRev [1,2,3,4] = [4,3,2,1] Foldr preserves ordering, foldl reverses it. cs7120(Prasad) L6-FOLD
13
foldr (fn (x,xs) => if p x then x::xs else xs) [] lis;
fun filter p lis = foldr (fn (x,xs) => if p x then x::xs else xs) [] lis; filter (fn x => x = 2) [1,2,3,2] fun filterNeg p lis = foldl (fn (x,xs) => if p x then xs else filterNeg (fn x => true) [“a”,”b”,”a”] These definitions inspect each element and collect their contribution filterNeg p = filter (not p) Basically these definitions illustrate that both foldl and foldr can be used to define filter. Fun filter p = foldl (fn (x,r) => if p x then else r) [] ; Examples illustrate atypical uses!!! cs7120(Prasad) L6-FOLD
14
foldr (fn (x,xs) => if p x then x::xs else []) [] lis;
fun takewhile p lis = foldr (fn (x,xs) => if p x then x::xs else []) [] lis; takewhile (fn x => x = 2) [2,2,3,1,2] fun dropwhile p lis = foldl (fn (x,xs) => if null xs andalso p x then [] else dropwhile (fn x => true) [1,2,3] takewhile definition using foldr inspects each element of the list from the right and drops the tail if the head element fails the test. It accomplishes the task inefficiently compared to the recursive definition that scans the list from the left. However, contrary to expectation, defining takewhile using foldl is not simple we need to retain the entire suffix irrespective of the value of the element. Similarly, dropwhile has a simple definition in terms of foldl, but not in terms of foldr. fun takewhileX p = foldl version needs additional marker which will restrict the use of the function. fun dropwhileX p = foldr version is not possible because the decision to drop an element in the list depends on the unseen part. cs7120(Prasad) L6-FOLD
15
Generalizing Operators without identity element
E.g., max, min, etc for which basis clause (for []) cannot be defined. fun foldl_1 f (x::xs) = foldl f x xs; fun foldr_1 f (x::[]) = x | foldr_1 f (x::y::ys) = f x (foldr_1 f (y::ys)) cs7120(Prasad) L6-FOLD
16
Laws : Identities If f is a binary function that is associative and a is an identity w.r.t. f, then foldr f a xs = foldl f a (rev xs) foldr [] [[1,2],[3,4],[5]] = [1,2,3,4,5] foldl [] (rev [[1,2],[3,4],[5]]) foldl [] [[1,2],[3,4],[5]] = [5,3,4,1,2] foldr (op +) 0 [1,2,3] = 6 foldl (op +) 0 [1,2,3] = 6 foldl (op +) 0 (rev [1,2,3]) = 6 Reverse not required because of commutativity of +. cs7120(Prasad) L6-FOLD
17
Laws : Identities If f is a binary function that is commutative and a is an identity w.r.t. f, then foldr f a xs = foldl f a xs foldr (op * ) 1 [1,2,3] = 6 foldl (op * ) 1 [1,2,3] = 6 foldr (fn(b,v)=> b andalso v) true [false] = false foldl (fn(b,v)=> b andalso v) true [false] foldr (op +) 0 [1,2,3] = 6 foldl (op +) 0 [1,2,3] = 6 foldl (op +) 0 (rev [1,2,3]) = 6 Reverse not required because of commutativity of +. cs7120(Prasad) L6-FOLD
18
Comparing foldl and foldr.
foldl (op +) 0 [1,2,3] = foldl (op +) 1 [2,3] = foldl (op +) 3 [3] = foldl (op +) 6 [] = 6 (foldl: Efficient) (Tail Recursive) foldr (op +) 0 [1,2,3] =1+foldr (op +) 0 [2,3] =3 + foldr (op +) 0 [3] =6 + foldr (op +) 0 [] foldl and t [t,f,t] = foldl and t [f,t] = foldl and f [t] = foldl and f [] = false (foldr: Efficient) (Short-circuit evaluation) foldr and t [t,f,t] = and t (foldr and t [f,t] = and f (foldr and t [t]) foldl + call by value : tail-recursive optimization (Accumulator technique) foldr + lazy evaluation : short-circuit operation cs7120(Prasad) L6-FOLD
19
scan (processing prefixes)
scan f a [x1,x2,…,xn] = [a,(f a x1),(f (f a x1) x2),…, (f … (f (f a x1) x2) …xn)] fun scan f a [] = [a] | scan f a xs = let val t = (scan f a (init xs)) in [(f (last t) (last xs))] end; scan : (‘a -> ‘b -> ‘a) -> ‘a -> ‘b list -> ‘a list fun scanv f a lis = foldl (fn (x,v) => [(f ((last v), x) )] ) [a] lis; scanv : (‘a * ‘b -> ‘a) -> ‘a -> ‘b list -> ‘a list scanv (op +) 0 [1,2,3,4,5] = [0,1,3,6,10,15] cs7120(Prasad) L6-FOLD
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.