Programming Languages. Thunks, Laziness, Streams, Memoization. Adapted from Dan Grossman s PL class, U. of Washington

Similar documents
CS 360 Programming Languages Day 14 Closure Idioms

CSE341: Programming Languages Lecture 15 Macros. Zach Tatlock Winter 2018

What is a macro. CSE341: Programming Languages Lecture 15 Macros. Example uses. Using Racket Macros. Zach Tatlock Winter 2018

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

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

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

Programming Languages. Function-Closure Idioms. Adapted from Dan Grossman's PL class, U. of Washington

Intro. Scheme Basics. scm> 5 5. scm>

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

Lexical vs. Dynamic Scope

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

CSE341 Spring 2016, Final Examination June 6, 2016

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

CSE341, Spring 2013, Final Examination June 13, 2013

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

Streams and Evalutation Strategies

CSE341: Programming Languages Winter 2018 Unit 5 Summary Zach Tatlock, University of Washington

CSE341 Spring 2017, Final Examination June 8, 2017

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

Racket. CSE341: Programming Languages Lecture 14 Introduction to Racket. Getting started. Racket vs. Scheme. Example.

CSE413: Programming Languages and Implementation Racket structs Implementing languages with interpreters Implementing closures

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

CSE341 Autumn 2017, Final Examination December 12, 2017

ITERATORS AND STREAMS 9

CSE 413 Languages & Implementation. Hal Perkins Winter 2019 Structs, Implementing Languages (credits: Dan Grossman, CSE 341)

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

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

CSE341 Spring 2017, Final Examination June 8, 2017

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

CS450 - Structure of Higher Level Languages

4.2 Variations on a Scheme -- Lazy Evaluation

CS61A Notes Disc 11: Streams Streaming Along

Discussion 11. Streams

Computer Science 21b (Spring Term, 2015) Structure and Interpretation of Computer Programs. Lexical addressing

Functional Programming. Pure Functional Languages

PAIRS AND LISTS 6. GEORGE WANG Department of Electrical Engineering and Computer Sciences University of California, Berkeley

From Syntactic Sugar to the Syntactic Meth Lab:

Sequentialising a concurrent program using continuation-passing style

CS 312. Lecture April Lazy Evaluation, Thunks, and Streams. Evaluation

Introduction to Functional Programming

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

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

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

CSE 505: Concepts of Programming Languages

miniadapton A Minimal Implementation of Incremental Computation in Scheme Dakota Fisher, Matthew Hammer, William E. Byrd, Matthew Might

User-defined Functions. Conditional Expressions in Scheme

Class 6: Efficiency in Scheme

Functional Programming. Pure Functional Languages

CS 360 Programming Languages Interpreters

CS61A Notes Week 9: Muta4on (solu4ons) Revenge of the Box- and- pointers

CS450: Structure of Higher Level Languages Spring 2018 Assignment 7 Due: Wednesday, April 18, 2018

COS 326 David Walker Princeton University

Sample Final Exam Questions

Racket: Macros. Advanced Functional Programming. Jean-Noël Monette. November 2013

SCHEME AND CALCULATOR 5b

Typed Racket: Racket with Static Types

Input, output, and sequence

Functional Languages. CSE 307 Principles of Programming Languages Stony Brook University

Programming Principles

CS1 Recitation. Week 1

Review Analyzing Evaluator. CS61A Lecture 25. What gets returned by mc-eval? (not analyzing eval) REVIEW What is a procedure?

CSE341: Programming Languages Lecture 17 Implementing Languages Including Closures. Dan Grossman Autumn 2018

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

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

CS61A Notes Week 6: Scheme1, Data Directed Programming You Are Scheme and don t let anyone tell you otherwise

Box-and-arrow Diagrams

Administrivia. Simple data types

QUIZ. What is wrong with this code that uses default arguments?

Streams and Lazy Evaluation in Lisp

(Provisional) Lecture 08: List recursion and recursive diagrams 10:00 AM, Sep 22, 2017

An Explicit Continuation Evaluator for Scheme

6.001 Notes: Section 17.5

CS 842 Ben Cassell University of Waterloo

Implementing Recursion

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

Scheme: Data. CS F331 Programming Languages CSCE A331 Programming Language Concepts Lecture Slides Monday, April 3, Glenn G.

CS152: Programming Languages. Lecture 7 Lambda Calculus. Dan Grossman Spring 2011

Project 1: Part 1. Project 1 will be to calculate orthogonal polynomials. It will have several parts. x = b± b 2 4ac., x 2 = b b 2 4ac.

Announcements. The current topic: Scheme. Review: BST functions. Review: Representing trees in Scheme. Reminder: Lab 2 is due on Monday at 10:30 am.

The Lambda Calculus. notes by Don Blaheta. October 12, A little bondage is always a good thing. sk

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

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

Discussion 4. Data Abstraction and Sequences

MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Computer Science. Issued: Wed. 26 April 2017 Due: Wed.

Exceptions. Errors and Exceptions. Dealing with exceptions. What to do about errors and exceptions

Lazy Evaluation and Parameter Transfer

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

CSE 341, Spring 2011, Final Examination 9 June Please do not turn the page until everyone is ready.

CS 61A Discussion 8: Scheme. March 23, 2017

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

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

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

CS 275 Name Final Exam Solutions December 16, 2016

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

The Art of Recursion: Problem Set 10

Putting the fun in functional programming

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

YOUR NAME PLEASE: *** SOLUTIONS ***

Scheme as implemented by Racket

Burning CDs in Windows XP

Transcription:

Programming Languages Thunks, Laziness, Streams, Memoization Adapted from Dan Grossman s PL class, U. of Washington

You ve been lied to Everything that looks like a function call in Racket is not necessarily a function. Everything that looks like a function is either A function call (as we thought) Or a special form Special forms: define, let, lambda, if, cond, and, or, Why can t these be functions? Recall the evaluation model for a function call: (f e1 e2 e3 ): evaluate e1 e2 to obtain values v1 v2, then evaluate f to get a closure, then evaluate the code of the closure with its arguments bound to v1 v2! Why would this not work for defining if?

Delayed evaluation In Racket, function arguments are eager (call by value) Special form arguments are lazy (call by need) Delay evaluation of the argument until we really need its value Why wouldn t these functions work? (define (my-if-bad x y z) (if x y z)) (define (fact-wrong n) (my-if-bad (= n 0) 1 (* n (fact-wrong (- n 1)))))

Thunks We know how to delay evaluation: put expression in a function definition! Because defining a function doesn t run the code until later. A zero-argument function used to delay evaluation is called a thunk As a verb: thunk the expression This works (though silly to re-define if like this): (define (my-if x y z) (if x (y) (z))) (define (fact n) (my-if (= n 0) (lambda() 1) (lambda() (* n (fact (- n 1))))))

Try this one Write a function called while that takes two arguments: a thunk called condition-thunk a thunk called body-thunk This function should emulate a while loop: test the conditionthunk, and if it's true, call the body thunk. Then test the condition thunk again, and if it's still true, run the body thunk. Write a while loop that prints the numbers 1 to 10. Define a function called my-length that takes one argument: a list. my-length should return the length of the list argument. Use a while loop.

Thunks Think of a thunk J as a promise to evaluate this expression as soon as we really need the value. (define result (compute-answer-to-life-univ-and-everything))! Would take a really long time to calculate result. (define result (lambda ()!(compute-answer-to-life-univ-and-everything)))! Note that just by defining a variable to hold the result doesn t mean we really need it yet. (if (= (result) 42) (do something) (do something else))! Now we need the value, so we compute it with (result).

Avoiding expensive computations Thunks let you skip expensive computations if they aren t needed (define result (lambda ()!(compute-answer-to-life-univ-and-everything)))! (if (want-to-know-answer?) (display (result)) (display too bad ))! Don t compute the answer to life, the universe, and everything unless you really want to know. Pro: More flexible than putting the computation itself inside of the if statement. Con: Every time we call (result), we compute the answer again! (Time waste, assuming the answer doesn t change)

; simulate a long computation time (define (compute-answer-to-life) (begin (sleep 3) 42)) ; create a thunk for the answer (define answer (lambda () (compute-answer-to-life)))) (answer) ; 3 second pause, then 42 (answer) ; 3 second pause again, then 42

Best of both worlds Assuming our expensive computation has no side effects, ideally we would: Not compute it until needed Remember the answer so future uses don t re-compute Known as lazy evaluation Languages where most constructs, including function calls, work this way are lazy languages Haskell Racket and Scheme are eager languages, but we can add support for laziness.

Delay and force (define (my-delay thunk) (mcons #f thunk)) (define (my-force p) (if (mcar p) (mcdr p) (begin (set-mcar! p #t) (set-mcdr! p ((mcdr p))) (mcdr p)))) An data structure represented by a mutable pair my-delay: create a promise data type for the thunk argument. #f in car means cdr is an unevaluated thunk This data type is called a promise. (not language-specific) my-force: return result of thunk (either run it and save the return value for later, or return previously-saved value). A promise represents a computation that is either already finished (in which case we remember the answer), or not executed yet (in which case we have some code [as a thunk] for when we need the answer).

Using promises ; simulate a long computation time (define (compute-answer-to-life) (begin (sleep 3) 42)) ; create a promise to hold a thunk for the answer (define answer2 (my-delay (lambda () (compute-answer-to-life)))) (my-force answer2) ; 3 second pause, then 42 (my-force answer2) ; instant 42

Racket promises Making our own promise data structure is still clunky because we have to explicitly wrap everything in a lambda. Racket has built-in promises (yay!) (delay e): special form that creates a promise to evaluate expression e as soon as its needed. (No extra lambda needed, b/c delay is a special form). (force p): evaluates a promise (something returned by delay) to compute whatever the value of the original expression is. Also caches the value so future forces will be very fast, even if the evaluation of the original expression is slow.

(require racket/promise)! (define (compute-answer-to-life)! (begin (sleep 3) 42))!! (define answer3 (delay (compute-answer-to-life)))! (force answer3) ; 3 second pause, then 42! (force answer3) ; instant 42!

Lazy lists, or streams One common use of delayed evaluation is to create a lazy list, or a stream. A stream is just like a list (a Racket list) in that it consists of two parts: the car and the cdr. Only difference is that the cdr is lazy (car is not usually lazy) In other words, the cdr is a promise to return the rest of the stream when its really needed. We need a new function to make a pair where the car is normal but the cdr is lazy.

Streams stream-cons: a special form that creates a new pair where the car is eager but the cdr is lazy alternatively, think of this as creating a new stream from a new first element and an existing stream just like regular cons creates a new list from a new first element and an existing list: (cons 1 '(2 3 4 5)) è '(1 2 3 4 5) (define (stream-cons first rest) (cons first (delay rest)) the above definition is correct in spirit, though wrong in syntax because we need to make stream-cons a special form so that rest will be thunked automatically.

Streams (define the-empty-stream '())!! (define (stream-null? stream)!! (null? stream))! (define (stream-car stream)!! (car stream))! (define (stream-cdr stream)! (force (cdr stream)))!

Let's try it out