Download presentation
Presentation is loading. Please wait.
1
Closures and Streams cs7100(Prasad) L11Clos
Great Reference: Abelson and Sussman : SICP Lecture introduces standard terms well-known in Functional Programming (languages) cs7100(Prasad) L11Clos
2
Contemporary Interest in Closures
The concept of closures was developed in the 1960s and was first fully implemented in 1975 as a language feature in the Scheme programming language to support lexically scoped first-class functions. Project Lambda makes it easier to write code for multi-core processors by adding closures to the Java language and extending the Java API to support parallelizable operations upon streamed data. Rick Hickey’s Clojure (a dialect of LISP for Java platform) is a pure functional language with support for rich set of data structures, and constructs for concurrent programming. cs7100(Prasad) L11Clos
3
Models of Evaluation Substitution-based (define (square x) (* x x))
((lambda (x y) (+ (square x) (square y))) (- 5 3) 5) (+ (square 2) (square 5)) (+ (* 2 2) (* 5 5)) ( ) 29 Equational reasoning by symbol manipulation; Arithmetic computation summarized without explicit rule invocation cs7100(Prasad) L11Clos
4
Expression Evaluation Options
To evaluate: (operator operand1 operand2 operand3 ...) Applicative-Order Evaluation (call by value) evaluate each of the sub-expressions. apply the leftmost result to the rest. Normal-Order Evaluation (call by name) apply the leftmost (lambda) sub-expression to the rest and expand. (Argument sub- expressions get evaluated when necessary.) These two mechanisms differ substantially for the following case: ( (lambda (x) 5) ( (lambda (x) (x x)) (lambda (x) (x x)) ) ) When computation terminates, both approaches have give the same value. However, normal order evaluation has more propensity to terminate than application order evaluation. (E.g., an argument evaluation, whose value is actually not needed, may not terminate.) Work of Alonzo Church in the 30s cs7100(Prasad) L11Clos
5
Models of Evaluation Environment-based ((lambda (x y)
(+ (square x) (square y))) (- 5 3) 5) (+ (square x) (square y)) x=2,y=5 (+ (* x x) x=2,y=5 (* x x) ) x=5,y=5 ( ) 29 Supports code reuse Substitution model specifies what to compute. Environment model computes it efficiently by only remembering those things that change. APPLICATIVE ORDER EVALUATION -- recursion no problem in substitution model cs7100(Prasad) L11Clos
6
An extended example (define square (lambda (x) (* x x)))
(define sum-of-squares (lambda (x y) (+ (square x) (square y)))) (define f (lambda (a) (sum-of-squares (+ a 1) (* a 2)))) (define (g) (let ((z 25)) z)) (g) 25 cs7100(Prasad) L11Clos
7
Initial Global Environment
Heap storage + Garbage collection vs Stack-based storage cs7100(Prasad) L11Clos
8
Executing (f 5) and (sum-of-squares 6 10)
Ref: SICP Static scoping: tree of environments Dynamic scoping: linear stack of environments Need for dynamic allocation and garbage collection => going beyond stack-based storage allocation-deallocation Refer to Queue-as-an-object code to see an example of closure : local variables in create() outlive its invocation as the variables are present in the other methods (closures) Only when all the methods are destroyed is the GC allowed to clean them … cs7100(Prasad) L11Clos
9
Delayed Evaluation : THUNKS
(define x (* 5 5)) x 25 (define y (lambda () (y) Partial Evaluation : CURRYING (define add (lambda (x) (lambda (y) (+ x y))) (define ad4 (add 4)) (ad4 8) 12 (define x 5) (define y (* x x)) (define x 6) y = 25 (define (y) (* x x)) (y) = 36 ML functions are inherently curried. Can consume arguments lazily. Ad4 retains the binding to x as 4. In stack-based implementation, Activation record x-4 would have been released when add-execution terminates. Here, it is allocated on heap for eventual descrution by the garbage collector. cs7100(Prasad) L11Clos
10
Closure and Models < (lambda (y) Substitution (lambda (y) (+ 4 y) )
Substitution model is inadequate for mutable data structures. Environment < (lambda (y) (+ x y)) , [x <- 4] > Need to distinguish location and contents of the location. cs7100(Prasad) L11Clos
11
Modular Designs with Lists
cs7100(Prasad) L11Clos
12
Higher-order functions and lists
Use of lists and generic higher-order functions enable abstraction and reuse Can replace customized recursive definitions with more readable definitions built using “library” functions The HOF approach may be less efficient. Promotes MODULAR DESIGNS – improves programmer productivity Modular Designs using Lists cs7100(Prasad) L11Clos
13
(define (even-fibs n) (define (next k) (if (> k n) ’() (let ((f (fib k))) (if (even? f) (cons f (next (+ k 1))) (next (+ k 1)) )) )) (next 0)) Take a number n and construct a list of first n even Fibonacci numbers. (define (fib n) (cond ((zero? n) 0) ((= n 1) 1) (else (+ (fib (- n 1)) (fib (- n 2)))) ) cs7100(Prasad) L11Clos
14
Abstract Description enumerate integers from 0 to n
compute the Fibonacci number for each integer filter them, selecting even ones accumulate the results using cons, starting with () Instead of using dissimilar customized recursive definitions for the problems, understand their similarities, and exploit it by defining and reusing common primitives. cs7100(Prasad) L11Clos
15
(define (filter pred seq) (cond ((null? seq) ’()) ((pred (car seq))
(cons (car seq) (filter pred (cdr seq)))) (else (filter pred (cdr seq))) )) (define (accumulate op init seq) (if (null? seq) init (op (car seq) (accumulate op init (cdr seq))) Typically, init and op in accumulate are connected. init op x = x op init = x cs7100(Prasad) L11Clos
16
(enum-interval 0 n)))))
(define (enum-interval low high) (if (> low high) ’() (cons low (enum-interval (+ low 1) high)) )) (define (even-fibs n) (accumulate cons ’() (filter even? (map fib (enum-interval 0 n))))) Accumulate part is redundant in this specific case. cs7100(Prasad) L11Clos
17
Streams: Motivation Streams simulated in Scheme and ML using closures. Streams are naturally supported through lazy evaluation in Haskell. For a classic account of streams refer to SICP (Abelson and Sussman) that clearly explains the following points: 1. Sequences and higher-order functions such as accumulate, map, filter, etc contribute to abstraction. 2. The need to support objects with states and assignments to have modular designs. (Problems with equality and sequencing.) 3. Streams as an alternative means to represent states through histories of values but without assignment. cs7100(Prasad) L11Clos
18
Modeling real-world objects (with state) and real-world phenomena
Use computational objects with local variables and implement time variation of states using assignments Alternatively, use sequences to model time histories of the states of the objects. Possible Implementations of Sequences Using Lists Using Streams Delayed evaluation (demand-based evaluation) useful (necessary) when large (infinite) sequences are considered. Electrical engineering signals : VHDL cs7100(Prasad) L11Clos
19
Streams : Equational Reasoning
(define s (cons 0 s)) Illegal. (Solution: infinite sequence of 0’s.) (0 . (0. (0. (0. … )))) (cf. Ada, Pascal,…) type s = record car : integer; cdr : s end; How do we represent potentially infinite structures? cs7100(Prasad) L11Clos
20
(0.(0.(0. … ))) (0. Function which when (0. ) (0. ) (0. . . . )
executed generates an infinite structure ) Recursive winding and unwinding ( ) ( ) ( ) cs7100(Prasad) L11Clos
21
>(define stream-car car) >(define (stream-cdr s) ( (cdr s) ) )
Unwrap by executing the second. >(define stream-zeros (cons 0 (lambda() stream-zeros) ) ) Wrap by forming closure (thunk). cs7100(Prasad) L11Clos
22
(stream-cdr stream-zeros) ) >(define (numbers-from n) (cons n
>(stream-car (stream-cdr stream-zeros) ) >(define (numbers-from n) (cons n (lambda () (numbers-from (+ 1 n)) ))) >(define stream-numbers (numbers-from 0) ) cs7100(Prasad) L11Clos
23
Recapitulating Stream Primitives
(define stream-car car) (define (stream-cdr s) ( (cdr s) ) ) (define (stream-cons x s) (cons x ( lambda ( ) s) ) ) (define the-empty-stream ’() ) (define stream-null? null?) These functions enable creation of streams with finite number of elements. For infinite streams, we need to use the technique given earlier for the seed-stream. cs7100(Prasad) L11Clos
24
(define (stream-filter p s) (cond ((stream-null? s) the-empty-stream)
((p (stream-car s)) (stream-cons (stream-car s) (stream-filter p (stream-cdr s)))) (else (stream-filter p (stream-cdr s))) )) (define (stream-enum-interval low high) (if (> low high) the-empty-stream (stream-cons low (stream-enum-interval (+ 1 low) high)))) cs7100(Prasad) L11Clos
25
(stream-enum-interval 100 1000))))
(stream-car (stream-cdr (stream-filter prime? (stream-enum-interval )))) (define (fibgen f1 f2) (cons f1 (lambda () (fibgen f2 (+ f1 f2))) )) (define fibs (fibgen 0 1)) Evaluate only as much as is necessary. Efficient. The following implementation is incorrect because of call by value evaluation. It would be okay in a lazy language. (define (fibgen f1 f2) (stream-cons f1 (fibgen f2 (+ f1 f2)) )) cs7100(Prasad) L11Clos
26
Factorial Revisited (define (trfac n) (letrec ( (iter (lambda (i a)
(if (zero? i) a (iter (- i 1) (* a i))))) ) (iter n 1) tail recursive factorial that can be automatically translated into an iteration. cs7100(Prasad) L11Clos
27
(define (ifac n) (let (( i n ) ( a 1 )) (letrec ( (iter (lambda ()
(if (zero? i) a (begin (set! a (* a i)) (set! i (- i 1)) (iter) )) ) (define (fac n) (let (( i n ) ( a 1 )) (letrec ( (iter (lambda () (if (zero? i) a (begin (set! i (- i 1)) (set! a (* a i)) (iter) )) ) (fac 4) = // ERROR The parallel assignment to formals is now made sequential. Because one of the formal effects the other, it is important that old values of a and i be used. Hence the ordering is constrained. There is also potential for bugs in rewriting tail-recursion as the corresponding iteration if ordering is messed-up. cs7100(Prasad) L11Clos
28
Factorial Stream (define (str n r) (cons r (lambda ()
(str (+ n 1) (* n r)) ) (define sfac (str 1 1)) (car ((cdr ((cdr ((cdr sfac)) )) )) ) … (stream-cdr … ) Demand driven generation of list elements. Caching/Memoing necessary for efficiency. Avoids assignment. str (“n” , “factorial n-1” ) We remember factorial n-1 to minimize computation ,1,2,6,24,… To compute the i-th factorial, this seems only constant factor inefficient than the iterative loop for the amount of computation. cs7100(Prasad) L11Clos
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.