Closures and Streams cs7100(Prasad) L11Clos

Slides:



Advertisements
Similar presentations
Programming with Lists
Advertisements

1 Scheme and Functional Programming Aaron Bloomfield CS 415 Fall 2005.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Getting started with ML ML is a functional programming language. ML is statically typed: The types of literals, values, expressions and functions in a.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
Lambda Calculus and Lisp PZ03J. Lambda Calculus The lambda calculus is a model for functional programming like Turing machines are models for imperative.
Chapter 3 Functional Programming. Outline Introduction to functional programming Scheme: an untyped functional programming language.
Cs7100(Prasad)L11Clos1 Closures and Streams. Contemporary Interest in Closures The concept of closures was developed in the 1960s and was first fully.
Chapter 15 Other Functional Languages. Copyright © 2007 Addison-Wesley. All rights reserved. Functional Languages Scheme and LISP have a simple syntax.
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
Cs776 (Prasad)L15strm1 Reasoning with Functional Programs Optimization by source to source transformation Well-founded induction Streams : Infinite lists.
Closures and Streams More on Evaluations CS784(pm)1.
CS 152: Programming Language Paradigms February 24 Class Meeting Department of Computer Science San Jose State University Spring 2014 Instructor: Ron Mak.
1 COMP313A Functional Programming (1). 2 Main Differences with Imperative Languages Say more about what is computed as opposed to how Pure functional.
CS535 Programming Languages Chapter - 10 Functional Programming With Lists.
1 Programming Languages (CS 550) Lecture 4 Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Cs3180 (Prasad)L156HOF1 Higher-Order Functions. cs3180 (Prasad)L156HOF2 Equivalent Notations (define (f x y) (… body …)) = (define f (lambda (x y) (…
Cs7120 (Prasad)L1-FP-HOF1 Functional Programming Basics Correctness > Clarity > Efficiency.
CS314 – Section 5 Recitation 9
Operational Semantics of Scheme
Functional Programming
CS314 – Section 5 Recitation 10
CS 3304 Comparative Languages
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Spring 2017.
Lecture 16 Streams continue Infinite Streams מבוא מורחב - שיעור 16.
CS 326 Programming Languages, Concepts and Implementation
6.001 SICP Variations on a Scheme
PPL Lecture Notes: Chapter 3 High-Order Procedures Revisited.
PPL Lazy Lists.
Introduction to Scheme
September 4, 1997 Programming Languages (CS 550) Lecture 6 Summary Operational Semantics of Scheme using Substitution Jeremy R. Johnson TexPoint fonts.
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Winter 2013.
Closures and Streams cs784(Prasad) L11Clos
COP4020 Programming Languages
Implementing Recursion
Env. Model Implementation
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Zach Tatlock Winter 2018.
6.001 SICP Data abstractions
Important Concepts from Clojure
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Spring 2013.
Important Concepts from Clojure
Streams Sections 3.5.1,3.5.2 Pages
Control Flow Chapter 6.
The Metacircular Evaluator
Lecture 18 Infinite Streams and
FP Foundations, Scheme In Text: Chapter 14.
PPL Sequence Interface.
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Spring 2016.
Procedural vs Functional Style
The Metacircular Evaluator
Closure Closure binds a first-class function and a lexical environment together This is a complex topic, so we will build up our understanding of it we.
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Autumn 2017.
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Autumn 2018.
6.001 SICP Streams – the lazy way
The Metacircular Evaluator (Continued)
6.001 SICP Further Variations on a Scheme
Streams, Delayed Evaluation and a Normal Order Interpreter
Streams and Lazy Evaluation in Lisp and Scheme
6.001 SICP Variations on a Scheme
Dan Grossman / Eric Mullen Autumn 2017
Announcements Quiz 5 HW6 due October 23
Important Concepts from Clojure
Assignments and Procs w/Params
COP4020 Programming Languages
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
More Scheme CS 331.
Brett Wortzman Summer 2019 Slides originally created by Dan Grossman
CSE341: Programming Languages Lecture 14 Thunks, Laziness, Streams, Memoization Dan Grossman Spring 2019.
Presentation transcript:

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

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

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)) (+ 4 25) 29 Equational reasoning by symbol manipulation; Arithmetic computation summarized without explicit rule invocation cs7100(Prasad) L11Clos

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

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 (+ 4 25) 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

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

Initial Global Environment Heap storage + Garbage collection vs Stack-based storage cs7100(Prasad) L11Clos

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

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

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

Modular Designs with Lists cs7100(Prasad) L11Clos

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

(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

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

(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

(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

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

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

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

(0.(0.(0. … ))) (0. Function which when (0. ) (0. ) (0. . . . ) executed generates an infinite structure ) Recursive winding and unwinding (0. ) (0. ) (0. . . . ) cs7100(Prasad) L11Clos

>(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

(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

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

(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

(stream-enum-interval 100 1000)))) (stream-car (stream-cdr (stream-filter prime? (stream-enum-interval 100 1000)))) (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

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

(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) = 0 // 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

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,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