PPL Lecture 4 Slides by Yaron Gonen, based on slides by Daniel Deutch and lecture notes by Prof. Mira Balaban
Midterm 2010 (define foo (let((f (lambda(x ) (+ 1 x)))) (lambda(x) (f x)))) תרגמו את ביטוי ה -let לביטוי ה -anonymous lambda מהו מס ' ה -closure שיווצרו ?
Today: High-Order Procedures (continued) Closures as returned values Delayed computation 4
Closures as Returned Values Number (+ x y y) [Num -> Num] (lambda (x) (+ x y y)) [Num -> [Num -> Num]] (lambda (y) (lambda (x) (+ x y y))) [Num -> Num] ((lambda (y) (lambda (x) (+ x y y))) 2) Number (((lambda (y) (lambda (x) (+ x y y))) 2) 5)
Example: derive ;Signature: deriv(f) ;Type: [[Number -> Number] -> [Number -> Number]] ;Example: for f(x)=x^3, the derivative is the function 3x^2, ;whose value at x=5 is 75. ;Tests: ((deriv cube) 5) ==> ~75 (define deriv (lambda (f) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx))))
Example: derive (define dx 0.001) (define deriv (lambda (f) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))) >deriv # >(deriv (lambda (x) (* x x x))) # >((deriv (lambda (x) (* x x x))) 5)
Compile Time vs. Runtime A basic questions when dealing with returned procedures More a question of ‘is it a procedure already? or do we need to evaluate this lambda expression?’ When a procedure depends on other procedures, it is preferred that these auxiliary closures are created at compile time
Compile Time vs Runtime (define sqr (lambda (x) (* x x))) (sqr 5) ((lambda (x) (* x x)) 5) Compile time Runtime
Example: n th deriv (define nth-deriv (lambda (f n) (lambda (x) (if (= n 0) (f x) ((nth-deriv (deriv f) (- n 1)) x))))) (define dx 0.001) (define deriv (lambda (f) (lambda (x) (/ (- (f (+ x dx)) (f x)) dx)))) reminder
(define nth-deriv (lambda (f n) (lambda (x) (if (= n 0) (f x) ((nth-deriv (deriv f) (- n 1)) x))))) (define nth-deriv (lambda (f n) (if (= n 0) f (nth-deriv (deriv f) (- n 1))))) >(define five-exp (lambda (x) (* x x x x x))) >(define fourth-deriv-of-five-exp (nth-deriv five-exp 4)) > fourth-deriv-of-five-exp # (define nth-deriv (lambda (f n) (if (= n 0) f (lambda (x) ((nth-deriv (deriv f) (- n 1)) x))))) (define nth-deriv (lambda (f n) (if (= n 0) f (deriv (nth-deriv f (- n 1))))))
Compile time vs Runtime We will always prefer compile-time, but sometimes its not possile (remember f_helper ?)
Delayed Computation With lambda we can delay the computation. We can abuse it to solve hard problems in an elegant way.
and and or special forms (and... ) (or... )
Example (if condition consequence alternative) ==> (or (and condition consequence) alternative)
Example > (define x 0) > (define y 6) > (or (and (zero? x) ) (/ y x)) But what about > (if (zero? x) #f #t) #f > (or (and (zero? x) #f) #t) #t
Example The fixed version: (if condition consequence alternative) ==> ((or (and condition (lambda () consequence)) (lambda () alternative))) Delayed!
Delayed Computation for obtaining Iterative Process New method for making iteration of recursion using high-order procedures
Recursive Factorial (define fact (lambda (n) (if (= n 0) 1 (* (fact (- n 1)) n))))
Iterative Factorial (define fact-iter (lambda (n prod) (if (= n 0) prod (fact-iter (- n 1) (* n prod)))))
Iterative Factorial with Delayed Computation (define fact$ (lambda (n cont) (if (= n 0) (cont 1) (fact$ (- n 1) (lambda (res) (cont (* n res)))))))
(fact$ 2 (lambda (x) x)) (fact$ 1 (lambda (res) ((lambda (x) x) (* 2 res)))) (fact$ 0 (lambda (res) ((lambda (res) ((lambda (x) x) (* 2 res))) (* 1 res)))) ((lambda (res) ((lambda (x) x) (* 2 res))) (* 1 res))) 1) ((lambda (res) ((lambda (x) x) (* 2 res))) 1) ((lambda (x) x) 2) 2
Polymorphic Procedure ; Signature: average-damp(f) ; Type: [[Number -> Number] -> [Number -> Number]] (define average-damp (lambda (f) (lambda (x) (average x (f x))))) ; Type: [Number*Number -> Number] (define average (lambda (x y) (/ (+ x y) 2)))
Polymorphic Procedure ; Type: ; [[T 1 -> T 2 ]* ; [T 1 * T 2 -> T 3 ] ; -> T 3 ] (define op-damp (lambda (f op) (lambda (x) (op x (f x))))) > (op-damp - +) # > ((op-damp - +) 3) 0 > (op-damp not (lambda (x y) (and x y))) # > ((op-damp not (lambda (x y) (and x y))) #t) #f
Polymorphic Procedures Procedures that can accept arguments and return values of varying types. Expressions that create these procedures are polymorphic expressions.
(Useful!!) Example ; Type: [T * List -> Boolean] (define member? (lambda (el l) (cond [(list? l) (or (member? el (car l)) (member? el (cdr l)))] [(eq? el l) #t] [else #f])))