Streams. CS21b: Structure and Interpretation of Computer Programs Spring Term, 2004

Similar documents
CS450 - Structure of Higher Level Languages

Normal Order (Lazy) Evaluation SICP. Applicative Order vs. Normal (Lazy) Order. Applicative vs. Normal? How can we implement lazy evaluation?

6.037 Lecture 7B. Scheme Variants Normal Order Lazy Evaluation Streams

Streams and Evalutation Strategies

Streams, Delayed Evaluation and a Normal Order Interpreter. CS 550 Programming Languages Jeremy Johnson

Problem Set 4: Streams and Lazy Evaluation

STREAMS 10. Basics of Streams. Practice with Streams COMPUTER SCIENCE 61AS. 1. What is a stream? 2. How does memoization work?

SCHEME 10 COMPUTER SCIENCE 61A. July 26, Warm Up: Conditional Expressions. 1. What does Scheme print? scm> (if (or #t (/ 1 0)) 1 (/ 1 0))

Introduction to Functional Programming

Principles of Programming Languages

ITERATORS AND STREAMS 9

STREAMS 10. Basics of Streams. Practice with Streams COMPUTER SCIENCE 61AS. 1. What is a stream?

4.2 Variations on a Scheme -- Lazy Evaluation

LECTURE 16. Functional Programming

CS61A Summer 2010 George Wang, Jonathan Kotker, Seshadri Mahalingam, Eric Tzeng, Steven Tang

Summer 2017 Discussion 10: July 25, Introduction. 2 Primitives and Define

CS 61A Interpreters, Tail Calls, Macros, Streams, Iterators. Spring 2019 Guerrilla Section 5: April 20, Interpreters.

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

CS61A Notes Disc 11: Streams Streaming Along

Programming Languages. Streams Wrapup, Memoization, Type Systems, and Some Monty Python

Spring 2018 Discussion 7: March 21, Introduction. 2 Primitives

CS 61A, Fall, 2002, Midterm #2, L. Rowe. 1. (10 points, 1 point each part) Consider the following five box-and-arrow diagrams.

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

Discussion 11. Streams

An introduction to Scheme

Overview. CS301 Session 3. Problem set 1. Thinking recursively

CS3L Summer 2011 Final Exam, Part 2 You may leave when finished; or, you must stop promptly at 12:20

Fall 2017 December 4, Scheme. Instructions

6.001 Notes: Section 17.5

Scheme. Functional Programming. Lambda Calculus. CSC 4101: Programming Languages 1. Textbook, Sections , 13.7

Building a system for symbolic differentiation

2.2 Hierarchical Data and the Closure Property

SCHEME 8. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. March 23, 2017

Delayed Expressions Fall 2017 Discussion 9: November 8, Iterables and Iterators. For Loops. Other Iterable Uses

Macros & Streams Spring 2018 Discussion 9: April 11, Macros

Fall 2017 Discussion 7: October 25, 2017 Solutions. 1 Introduction. 2 Primitives

Fall 2017 December 4, 2017

Project 2: Scheme Interpreter

CMPSCI 250: Introduction to Computation. Lecture #14: Induction and Recursion (Still More Induction) David Mix Barrington 14 March 2013

6.184 Lecture 4. Interpretation. Tweaked by Ben Vandiver Compiled by Mike Phillips Original material by Eric Grimson

Introduction to Scheme

An Explicit-Continuation Metacircular Evaluator

SCHEME AND CALCULATOR 5b

Deferred operations. Continuations Structure and Interpretation of Computer Programs. Tail recursion in action.

Lisp Basic Example Test Questions

SCHEME 7. 1 Introduction. 2 Primitives COMPUTER SCIENCE 61A. October 29, 2015

Principles of Programming Languages

Organization of Programming Languages CS3200/5200N. Lecture 11

1.3. Conditional expressions To express case distinctions like

Programming Principles

Procedural abstraction SICP Data abstractions. The universe of procedures forsqrt. Procedural abstraction example: sqrt

TAIL CALLS, ITERATORS, AND GENERATORS 11

Repetition Through Recursion

This exam is worth 70 points, or about 23% of your total course grade. The exam contains 15 questions.

Functional programming with Common Lisp

The University of Nottingham

CS 360 Programming Languages Interpreters

Why do we need an interpreter? SICP Interpretation part 1. Role of each part of the interpreter. 1. Arithmetic calculator.

Class 6: Efficiency in Scheme

SCHEME The Scheme Interpreter. 2 Primitives COMPUTER SCIENCE 61A. October 29th, 2012

CSc 520 Principles of Programming Languages

Administrivia. Simple data types

Interpreters and Tail Calls Fall 2017 Discussion 8: November 1, 2017 Solutions. 1 Calculator. calc> (+ 2 2) 4

TAIL RECURSION, SCOPE, AND PROJECT 4 11

COP4020 Programming Assignment 1 - Spring 2011

regsim.scm ~/umb/cs450/ch5.base/ 1 11/11/13

CIS 194: Homework 6. Due Wednesday, 4 March. Fibonacci numbers. It s all about being lazy.

Streams and Lazy Evaluation in Lisp

Structure and Interpretation of Computer Programs

Lecture 5: Lazy Evaluation and Infinite Data Structures

Building a system for symbolic differentiation

Lecture #24: Programming Languages and Programs


Functional Programming Languages (FPL)

CSE Programming Languages Midterm - Winter 2010

Fall 2018 Discussion 8: October 24, 2018 Solutions. 1 Introduction. 2 Primitives

Lecture 09: Data Abstraction ++ Parsing is the process of translating a sequence of characters (a string) into an abstract syntax tree.

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

Functional Programming. Pure Functional Programming

Computer Science Foundation Exam. Dec. 19, 2003 COMPUTER SCIENCE I. Section I A. No Calculators! KEY

61A LECTURE 22 TAIL CALLS, ITERATORS. Steven Tang and Eric Tzeng July 30, 2013

Extra Lecture #7: Defining Syntax

Scheme Quick Reference

Putting the fun in functional programming

Syntactic Sugar: Using the Metacircular Evaluator to Implement the Language You Want

6.037 Lecture 4. Interpretation. What is an interpreter? Why do we need an interpreter? Stages of an interpreter. Role of each part of the interpreter

CS61A Notes 02b Fake Plastic Trees. 2. (cons ((1 a) (2 o)) (3 g)) 3. (list ((1 a) (2 o)) (3 g)) 4. (append ((1 a) (2 o)) (3 g))

CS61A Midterm 2 Review (v1.1)

CS1 Recitation. Week 2

Part I Basic Concepts 1

A Genetic Algorithm Implementation

Structure and Interpretation of Computer Programs

Implementing Coroutines with call/cc. Producer/Consumer using Coroutines

Recursion. Lars-Henrik Eriksson. Functional Programming 1. Based on a presentation by Tjark Weber and notes by Sven-Olof Nyström

Quicksort. Alternative Strategies for Dividing Lists. Fundamentals of Computer Science I (CS F)

Scheme Quick Reference

Sometimes it s good to be lazy

CPSC 121 Some Sample Questions for the Final Exam Tuesday, April 15, 2014, 8:30AM

CSE 413 Winter 2001 Midterm Exam

Functional Programming. Pure Functional Languages

Transcription:

Streams CS21b: Structure and Interpretation of Computer Programs Spring Term, 2004

We ve already seen how evaluation order can change behavior when we program with state. Now we want to investigate how evaluation order can change efficiency -- and more important, how changing evaluation order can open the door to a whole new perspective on data structures. In particular, infinite data structures...

Streams and stream processing We have already seen the "signal processing" or "circuit" style of programming: (sum (map square (filter prime? (enumerate-interval 2 1000000)))) Now, what about the "waste motion" of the following? (car (cdr (map square (filter prime? (enumerate-interval 2 1000000))))) Instead: produce elements of a new kind of list -- a stream -- on a "need to know" basis, while preserving the standard invariants (stream-car (cons-stream x y)) = x (stream-cdr (cons-stream x y)) = y Also introduce the-empty-stream, stream-null? etc.

Building blocks: (define (stream-ref s n) (if (= n 0) (stream-car s) (stream-ref (stream-cdr s) (- n 1)))) (define (stream-map proc s) (if (stream-null? s) the-empty-stream (cons-stream (proc (stream-car s)) (stream-map proc (stream-cdr s))))) (define (stream-for-each proc s)...) (define (display-stream s) (stream-for-each (lambda (x) (display x) (newline)) s)) What changes by changing just a name? Nothing. We need a new implementation...

We need a new implementation... (cons-stream a b) =def= (cons a (delay b))...but how do we delay evaluation?... (delay b) =def= (lambda () b) Thus (cons-stream a b) =def= (cons a (lambda () b)) [Think of this as syntactic sugar.] Cons-stream gets a pair, evaluates the first argument, but builds a procedure which can evaluate the second argument (if called). What does this mean in terms of environment diagrams? (define (stream-car stream) (car stream)) or if you prefer, (define stream-car car) (define (stream-cdr stream) (force (cdr stream))) where (force s) =def= (s) thus (define (stream-cdr stream) ((cdr stream)))

Stream implementation in action: (stream-car (stream-cdr (stream-enumerate-interval 2 1000000))) (stream-car (stream-cdr (stream-filter prime? (stream-enumerate-interval 2 1000000)))) Note (define (stream-enumerate-interval from to) (if (> from to) the-empty-stream (cons-stream from (stream-enumerate-interval (+ from 1) to)))) Efficiency issues (define s (stream-filter prime? (stream-enumerate-interval 2 1000000))) (+ (select 1000 s) (select 1001 s)) Notice work gets repeated. Also, we are using: (define (select n stream) (if (= n 0) (stream-car stream) (select (- n 1) (stream-cdr stream)))) Answer: memoization

A memoized version of streams (define head car) ;Value: head (define (tail s) (let ((t (cdr s))) (if (or (pair? t) (null? t)) t (begin (set-cdr! s (t)) (cdr s))))) ;Value: tail (define (ints n) (cons n (lambda () (ints (1+ n))))) ;Value: ints (define N (ints 1)) ;Value: N N ;Value: (1. #[compound-procedure 2]) (tail N) ;Value: (2. #[compound-procedure 4]) N ;Value: (1 2. #[compound-procedure 4]) (tail (tail N)) ;Value: (3. #[compound-procedure 6]) N ;Value: (1 2 3. #[compound-procedure 6])

Memoization: (define (memo-proc proc) (let ((already-run? #f) (result #f)) (lambda () (if (not already-run?) (begin (set! result (proc)) (set! already-run? #t) result) result)))) Question: what does this look like in the environment model? Now instead, use the syntactic sugar: (delay b) =def= (memo-proc (lambda () b))

Infinite streams Lists are inductively defined, and every one of them has finite length. (Prove it!) In contrast, streams may be infinite in length! (define ones (cons-stream 1 ones)) Compare this with (define ones (cons 1 ones)) [what happens here?] (define (integers-from n) (cons-stream n (integers-from (+ n 1)))) (select 100 (integers-from 101))

Infinite streams, cont. Integers not divisible by 7: (define integers (integers-from 0)) (define (divisible? x y) (= (remainder x y) 0)) (define no-sevens (stream-filter (lambda (x) (not (divisible? x 7))) integers)) Fibonacci numbers, yet again: (define (fibgen a b) (cons-stream a (fibgen b (+ a b)))) (define fibs (fibgen 0 1)) Primes: (define (sieve stream) (cons-stream (stream-car stream) (sieve (stream-filter (lambda (x) (not (divisible? x (stream-car stream)))) (stream-cdr stream))))) (define primes (sieve (integers-from 2)))

Defining streams implicitly Assume the streams are infinite... (define (add-streams s1 s2) (cons-stream (+ (stream-car s1) (stream-car s2)) (add-streams (stream-cdr s1) (stream-cdr s2)))) (define integers (cons-stream 1 (add-streams ones integers))) (define fibs (cons-stream 0 (cons-stream 1 (add-streams (stream-cdr fibs) fibs))))

Defining streams implicitly (define primes (cons-stream 2 (stream-filter prime? (integers-from 3)))) (define (prime? n) (define (iter ps) (if (> (square (stream-car ps)) n) #t (if (divisible? n (stream-car ps)) #f (iter (stream-cdr ps))))) (iter primes)) Note the list of primes is use to generate candidate prime divisors -- we just need to "prime the pump" (no pun intended...)

Defining infinite data structures An infinite data structure is just a finite piece of ordinary data structure, together with a rule (i.e., procedure) for generating more of the structure. A simple example: infinite binary trees. Syntactic sugar: (make-tree root left right) =def= (list root (lambda () left) (lambda () right)) (define root car) (define (left-tree tree) ((cadr tree))) (define (right-tree tree) ((caddr tree))) Suppose S1 and S2 are streams, and you want to make a tree of all the possible interleavings of S1 and S2... (define (interleave S1 S2 rootvalue) (make-tree rootvalue (interleave (stream-cdr S1) S2 (stream-car S1)) (interleave S1 (stream-cdr S2) (stream-car S2))))

Joint bank accounts: Don t cross the streams! One-client bank account, with a stream of deposits (- means withdrawal) (define (make-deposit-account balance deposit-stream) (cons-stream balance (make-deposit-account (+ balance (head deposit-stream)) (tail deposit-stream)))) Two-client account (with two streams of deposits): (define (joint-account balance harry-stream anne-stream) (make-tree balance (joint-account (+ balance (head harry-stream)) (tail harry-stream) anne-stream) (joint-account (+ balance (head anne-stream)) harry-stream (tail anne-stream)))) Every path through the tree indicates a specific interleaving...

Mapping a function over an infinite tree: (define (map-tree proc tree) (list (proc (root tree)) (lambda () (map-tree proc (left-tree tree))) (lambda () (map-tree proc (right-tree tree))))) Picking a (stream) path through an infinite tree: (define (random-path-stream tree) (cons-stream (root tree) (random-path-tree ((pick-random (subtrees tree))))))

What s the difference between programs and data? Here s a program: (define (square n) (* n n))

What s the difference between programs and data? (Philosophical analogue: do we represent knowledge extensionally [list], declaratively [specification of what is], or procedurally [how to]?) Here s a program: (define (square n) (* n n)) No, this is data! You see, there s an infinite stream of squares, and (square n) selects the nth element of this stream... Maybe a better differentiation is... static vs. dynamic?