PPL Lecture Notes Chapter 3 HighOrder Procedures Revisited

  • Slides: 42
Download presentation
PPL Lecture Notes: Chapter 3 High-Order Procedures Revisited

PPL Lecture Notes: Chapter 3 High-Order Procedures Revisited

Remember let ? (define f (lambda ( x y) (let ((a (+ 1 (*

Remember let ? (define f (lambda ( x y) (let ((a (+ 1 (* x y))) (b (- 1 y))) (+ (* x (square a)) (* y b) (* a b))))) (define f (lambda (x y) ((lambda (a b) (+ (* x (square a)) (* y b) (* a b))) (+ 1 (* x y)) (- 1 y)) ))

applicative-eval[ (f 3 1) ] ==>* Substitute: <body of f>○{x = 3, y =

applicative-eval[ (f 3 1) ] ==>* Substitute: <body of f>○{x = 3, y = 1} ==> applicative-eval[ ((lambda (a b) (+ (* 3 (square a)) (* 1 b) (* a b))) (+ 1 (* 3 1)) (- 1 1)) ] ==>* applicative-eval[ (+ (* 3 16) (* 1 0) (* 4 0)) ] ==> 48

Local Procedures (define f (λ (x y) (let ((f-helper (lambda (a b) (+ (*

Local Procedures (define f (λ (x y) (let ((f-helper (lambda (a b) (+ (* x (* a a)) (* y b) (* a b))) ) ) (f-helper (+ 1 (* x y)) (- 1 y)))))

applicative-eval[ (f 3 1) ] ==> applicative-eval[ f ] ==> <proc (x y) (let.

applicative-eval[ (f 3 1) ] ==> applicative-eval[ f ] ==> <proc (x y) (let. . . )> applicative-eval[ 3 ] ==> 3 applicative-eval[ 1 ] ==> 1 Substitute: <body of f>○{x = 3, y = 1} ==> applicative-eval[ ( (lambda (f-helper) (f-helper (+ 1 (* 3 1)) (- 1 1))) (lambda (a b) (+ (* 3 (square a)) (* 1 b) (* a b))) ) ] ==>* applicative-eval[ ( <proc (a b)(+ (* 3 (square a)) (* 1 b) (* a b)) > (+ 1 (* 3 1)) (- 1 1)) ] ==>* applicative-eval[ (+ (* 3 16) (* 1 0) (* 4 0)) ] ==>* 48

LET and Recursive Procedures (define fact (λ (n) (let ((iter (lambda (prod c) (if

LET and Recursive Procedures (define fact (λ (n) (let ((iter (lambda (prod c) (if (> c n) prod (iter (* c prod) (+ c 1)))) )) (iter 1 1))))

(define fact (λ (n) (let ((iter (λ (prod c) (if (> c n) prod

(define fact (λ (n) (let ((iter (λ (prod c) (if (> c n) prod (iter (* c prod) (+ c 1)))))) (iter 1 1)))) (define fact (λ (n) ( (λ (iter) (iter 1 1)) (λ (prod c) (if (> c n) prod (iter (* c prod) (+ c 1)))))))

LET and Recursive Procedures (define fact (λ (n 1) (let ((iter 2 (lambda (prod

LET and Recursive Procedures (define fact (λ (n 1) (let ((iter 2 (lambda (prod 3 c 3) (if (> c 3 n 1) prod 3 (iter (* c 3 prod 3) (+ c 3 1)))) )) (iter 2 1 1))))

LETREC “For local recursive functions there is a special operator letrec, similar to let,

LETREC “For local recursive functions there is a special operator letrec, similar to let, and used only for local procedure (function) definitions. It’s syntax is the same as that of let. But, the scope of the local procedure declarations includes all of the initialization procedures!”

LETREC (define fact (λ (n) (letrec ((iter (lambda (prod c) (if (> c n)

LETREC (define fact (λ (n) (letrec ((iter (lambda (prod c) (if (> c n) prod (iter (* c prod) (+ c 1)))) )) (iter 1 1))))

Usage Agreement • let: non-procedure locals • letrec: procedural locals • The substitution model

Usage Agreement • let: non-procedure locals • letrec: procedural locals • The substitution model does not account for local recursive procedures

The Sequence Interface • OOP abstracts data. • FP is better: abstracts behavior: sequence

The Sequence Interface • OOP abstracts data. • FP is better: abstracts behavior: sequence oprtations • Java 8 new feature is sequence operations… Scheme had it for years!

What is Sequence Interface? • ADT for lists • In other words: a barrier

What is Sequence Interface? • ADT for lists • In other words: a barrier between clients running sequence applications and their implementations • Abstracts-away element by element manipulation

Map • Applies a procedure to all elements of a list. Returns a list

Map • Applies a procedure to all elements of a list. Returns a list as a result ; Signature: map(proc, sequence) ; Purpose: Apply ’proc’ to all ’sequence’. ; Type: [[T 1 -> T 2]*LIST(T 1) -> LIST(T 2)] ; Examples: ; (map abs (list -10 2. 5 -11. 6 17)) ; ==> (10 2. 5 11. 6 17) ; (map (lambda (x) (* x x)) (list 1 2 3 4)) ; ==> (1 4 9 16) ; Post-condition: For all i=1. . length(sequence): resulti = proc(sequencei)

Map in Java? A little better: List<Integer> my. Sequence = new Linked. List<> {1,

Map in Java? A little better: List<Integer> my. Sequence = new Linked. List<> {1, 2, 3, 4}; my. Sequence. map((lambda (i) (sysout i))) Perfect!

Map Example: scale-list Scaling list of numbers by a factor ; Signature: scale-list(items, factor)

Map Example: scale-list Scaling list of numbers by a factor ; Signature: scale-list(items, factor) ; Purpose: Scaling elements of a number list by a factor. ; Type: [LIST(Number)*Number -> LIST(Number)] > (scale-list (list 1 2 3 4 5) 10) (10 20 30 40 50)

Implementation of scale-list No Map (define scale-list (lambda (items factor) (if (empty? items) empty

Implementation of scale-list No Map (define scale-list (lambda (items factor) (if (empty? items) empty (cons (* (car items) factor) (scale-list (cdr items) factor))))) (define scale-list (lambda (items factor) (map (lambda (x) (* x factor)) items))

Map Example: scale-tree Mapping over hierarchical lists >(scale-tree (list 1 (list 2 (list 3

Map Example: scale-tree Mapping over hierarchical lists >(scale-tree (list 1 (list 2 (list 3 4) 5) (list 6 7)) 10) (10 (20 (30 40) 50) (60 70))

Implementation of scale-tree No Map (define scale-tree (lambda (tree factor) (cond [(empty? tree) empty]

Implementation of scale-tree No Map (define scale-tree (lambda (tree factor) (cond [(empty? tree) empty] [(not (list? tree)) (* tree factor)] [else (cons (scale-tree (car tree) factor) (scale-tree (cdr tree) factor))]))) (define scale-tree (lambda (tree factor) (map (lambda (sub-tree) (if (list? sub-tree) (scale-tree sub-tree factor) (* sub-tree factor))) tree)))

Map in Java List<Integer> list = Arrays. as. List(1, 2, 3, 4, 5, 6,

Map in Java List<Integer> list = Arrays. as. List(1, 2, 3, 4, 5, 6, 7); //Old way: for(Integer n: list) { System. out. println(n); } //New way: list. for. Each(n -> System. out. println(n)); //Scheme (map list (lambda(n) (display n))

Implementation of Map ; Signature: map(proc, items) ; Purpose: Apply ’proc’ to all ’items’.

Implementation of Map ; Signature: map(proc, items) ; Purpose: Apply ’proc’ to all ’items’. ; Type: [[T 1 -> T 2]*LIST(T 1) -> LIST(T 2)] (define map (lambda (proc items) (if (null? items) (list) (cons (proc (car items)) (map proc (cdr items))))))

A More General Map • So far, the procedure can get only a single

A More General Map • So far, the procedure can get only a single parameter: an item in the list • Map in Scheme is more general: n-ary procedure and n lists (with same length) Example: > (map + (list 1 2 3) (list 40 50 60) (list 700 800 900)) (741 852 963)

Filter Homogenous List Signature: filter(predicate, sequence) Purpose: return a list of all sequence elements

Filter Homogenous List Signature: filter(predicate, sequence) Purpose: return a list of all sequence elements that satisfy the predicate Type: [[T-> Boolean]*LIST(T) -> LIST(T)] Example: (filter odd? (list 1 2 3 4 5)) ==> (1 3 5) Post-condition: result = sequence {el|el∈sequence and not(predicate(el))}``

Accumulate Procedure Application Signature: accumulate(op, initial, sequence) Purpose: Accumulate by ’op’ all sequence elements,

Accumulate Procedure Application Signature: accumulate(op, initial, sequence) Purpose: Accumulate by ’op’ all sequence elements, starting (ending) with ’initial’ Type: [[T 1*T 2 -> T 2]*T 2*LIST(T 1) -> T 2] Examples: (accumulate + 0 (list 1 2 3 4 5)) ==> 15 (accumulate * 1 (list 1 2 3 4 5)) ==> 120

Interval Enumeration Signature: enumerate-interval(low, high) Purpose: List all integers within an interval: Type: [Number*Number

Interval Enumeration Signature: enumerate-interval(low, high) Purpose: List all integers within an interval: Type: [Number*Number -> LIST(Number)] Example: (enumerate-interval 2 7) ==> (2 3 4 5 6 7) Pre-condition: high > low Post-condition: result = (low low+1. . . high)

Enumerate Tree Signature: enumerate-tree(tree) Purpose: List all leaves of a number tree Type: [LIST

Enumerate Tree Signature: enumerate-tree(tree) Purpose: List all leaves of a number tree Type: [LIST union T -> LIST(Number)] Example: (enumerate-tree (list 1 (list 2 (list 3 4)) 5)) ==> (1 2 3 4 5) Post-condition: result = flatten(tree)

Sum-odd-squares ; Signature: sum-odd-squares(tree) ; Purpose: return the sum of all odd square leaves

Sum-odd-squares ; Signature: sum-odd-squares(tree) ; Purpose: return the sum of all odd square leaves ; Type: [LIST -> Number] ; tree leaves ---> ; filter: odd? ---> ; map: square ---> ; accumulate: +, 0. (define sum-odd-squares (lambda (tree) (accumulate + 0 (map square (filter odd? (enumerate-tree))))))

Even Fibonacci Numbers Without sequence operations: With sequence operations: (define even-fibs (lambda (n) (letrec

Even Fibonacci Numbers Without sequence operations: With sequence operations: (define even-fibs (lambda (n) (letrec ((next (lambda(k) (if (> k n) (list) (let ((f (fib k))) (if (even? f) (cons f (next (+ k 1)))))))) (next 0)))) (define even-fibs (lambda (n) (accumulate cons (list) (filter even? (map fib (enumerate-interval 0 n))))))

Filter implementation ; ; Signature: filter(predicate, sequence) ; ; Purpose: return a list of

Filter implementation ; ; Signature: filter(predicate, sequence) ; ; Purpose: return a list of all sequence elements that satisfy the predicate ; ; Type: [[T-> Boolean]*LIST(T) -> LIST(T)] (define filter (lambda (predicate sequence) (cond ((empty? sequence) ((predicate (car sequence)) (cons (car sequence) (filter predicate (cdr sequence)))) (else (filter predicate (cdr sequence))))))

Accumulate Implementation ; ; Signature: accumulate(op, initial, sequence) ; ; Purpose: Accumulate by ’op’

Accumulate Implementation ; ; Signature: accumulate(op, initial, sequence) ; ; Purpose: Accumulate by ’op’ all sequence elements, starting (ending) ; ; with ’initial’ ; ; Type: [[T 1*T 2 -> T 2]*T 2*LIST(T 1) -> T 2] (define accumulate (lambda (op initial sequence) (if (null? sequence) initial (op (car sequence) (accumulate op initial (cdr sequence))))))

Enumerate-interval Implementation ; ; Signature: enumerate-interval(low, high) ; ; Purpose: List all integers within

Enumerate-interval Implementation ; ; Signature: enumerate-interval(low, high) ; ; Purpose: List all integers within an interval: ; ; Type: [Number*Number -> LIST(Number)] (define enumerate-interval (lambda (low high) (if (> low high) (list) (cons low (enumerate-interval (+ low 1) high)))))

Enumerate-Tree Implementation ; ; Signature: enumerate-tree(tree) ; ; Purpose: List all leaves of a

Enumerate-Tree Implementation ; ; Signature: enumerate-tree(tree) ; ; Purpose: List all leaves of a number tree ; ; Type: [LIST union T -> LIST(Number)] (define enumerate-tree (lambda (tree) (cond ((null? tree) (tree)) ((not (list? tree)) (list tree)) (else (append (enumerate-tree (car tree)) (enumerate-tree (cdr tree)))))))

Haskell Curry

Haskell Curry

Partial Evaluation using Function Currying • Technique for turning a function with n parameters

Partial Evaluation using Function Currying • Technique for turning a function with n parameters to n functions with a single parameter • Good for partial evaluation

Currying ; Type: [Number*Number -> Number] (define add (λ (x y) (+ x y)))

Currying ; Type: [Number*Number -> Number] (define add (λ (x y) (+ x y))) ; Type: [Number -> Number]] (define c-add (λ (x) (λ (y) (add x y)))) (define add 3 (c-add 3)) (add 3 4) 7

Currying ; Signature: c-sum(term) ; Type: ; [[Number -> Number] -> ; [[Number ->

Currying ; Signature: c-sum(term) ; Type: ; [[Number -> Number] -> ; [[Number -> number] -> ; [Number*Number ->Number]]] (define c-sum (lambda (term) (lambda (next) (lambda (a b) (sum term a next b)))))

Naïve and non-Naïve Currying (define add-fib (lambda (x y) (+ (fib x) y))) (define

Naïve and non-Naïve Currying (define add-fib (lambda (x y) (+ (fib x) y))) (define c-add-fib (lambda (x) (lambda (y) (+ (fib x) y)))) (define c-add-fib (lambda (x) (let ((fib-x (fib x))) (lambda (y) (+ fib-x y)))))

Naïve and non-Naïve Currying (define c-expt (λ (b) (lambda (b) (λ (e) (letrec (if

Naïve and non-Naïve Currying (define c-expt (λ (b) (lambda (b) (λ (e) (letrec (if (= e 0) ([helper 1 (λ (e) (* (if b (= e 0) ((c-expt b) 1 (- e 1))))))) (* b (helper (- e 1)))))]) helper)))

Curried Map Delayed List Naïve Version: ; Signature: c-map-proc(proc) ; Purpose: Create a delayed

Curried Map Delayed List Naïve Version: ; Signature: c-map-proc(proc) ; Purpose: Create a delayed map for ’proc’. ; Type: [[T 1 -> T 2] -> [LIST(T 1) -> LIST(T 2)]] (define c-map-proc (lambda (proc) (lambda (lst) (if (empty? lst) lst (cons (proc (car lst)) ((c-map-proc) (cdr lst)))))))

Curried Map – delay the list (define c-map-proc (lambda (proc) (letrec ((iter (lambda (lst)

Curried Map – delay the list (define c-map-proc (lambda (proc) (letrec ((iter (lambda (lst) (if (empty? lst) lst (cons (proc (car lst)) (iter (cdr lst))))))) iter)))

Curried Map – delay the proc ; ; Signature: c-map-list(lst) ; ; Purpose: Create

Curried Map – delay the proc ; ; Signature: c-map-list(lst) ; ; Purpose: Create a delayed map for ’lst’. ; ; Type: [LIST(T 1) -> [[T 1 -> T 2] -> LIST(T 2)]] (define c-map-list (lambda (lst) (if (empty? lst) (lambda (proc) lst) ; c-map-list returns a procedure (let ((mapped-cdr (c-map-list (cdr lst)))) ; Inductive Currying (lambda (proc) (cons (proc (car lst)) (mapped-cdr proc)))))))

(define c-map-lis (c-map-list ‘(1 2)) t ( λ ( l) mapped-cdr (if (null? l)

(define c-map-lis (c-map-list ‘(1 2)) t ( λ ( l) mapped-cdr (if (null? l) (c-map-list ‘(2)) (λ (proc) l) mapped-cdr (let (c-map-list ‘()) ((mapped-cdr (λ (p) l) (c-map-list (cdr l)))) ( λ ( p r o c) (λ (p) (cons (proc (car l)) (p 2) (mapped-cdr proc) )))))) ((λ (p) l) p)))) (λ (p) (cons (p 1) ((λ (p) (cons (p 2) ((λ (p) l) p)))) p)