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

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

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

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

ITERATORS AND STREAMS 9

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

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

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

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

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

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

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

SCHEME AND CALCULATOR 5b

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

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

Principles of Programming Languages Topic: Functional Programming Professor L. Thorne McCarty Spring 2003

CS450 - Structure of Higher Level Languages

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

LECTURE 16. Functional Programming

User-defined Functions. Conditional Expressions in Scheme

Functional Programming. Pure Functional Programming

Functional Programming

Design and Analysis of Algorithms Prof. Madhavan Mukund Chennai Mathematical Institute. Module 02 Lecture - 45 Memoization

An introduction to Scheme

Functional programming in LISP

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

Concepts of programming languages

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

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

CS1102: Macros and Recursion

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

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

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

Problem Set 4: Streams and Lazy Evaluation

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

INTERPRETERS 8. 1 Calculator COMPUTER SCIENCE 61A. November 3, 2016

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


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

Random Testing in 321

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

CSE 341 Section 7. Eric Mullen Spring Adapted from slides by Nicholas Shahan, Dan Grossman, and Tam Dang

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

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

CSE341 Autumn 2017, Final Examination December 12, 2017

CS 360: Programming Languages Lecture 10: Introduction to Haskell

CS 320: Concepts of Programming Languages

Programming with Math and Logic

Lisp. Versions of LISP

CS115 - Module 10 - General Trees

6.001 Notes: Section 8.1

CS61A Midterm 2 Review (v1.1)

Introduction to Functional Programming

CS 320 Homework One Due 2/5 11:59pm

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

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Modern Programming Languages. Lecture LISP Programming Language An Introduction

MORE SCHEME. 1 What Would Scheme Print? COMPUTER SCIENCE MENTORS 61A. October 30 to November 3, Solution: Solutions begin on the following page.

Algorithm Design and Recursion. Search and Sort Algorithms

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

An Explicit-Continuation Metacircular Evaluator

Structure and Interpretation of Computer Programs

INTERPRETERS AND TAIL CALLS 9

6.001 Notes: Section 17.5

Discussion 11. Streams

Scheme Basics > (butfirst '(help!)) ()

Functional Programming. Pure Functional Languages

PROBLEM SOLVING 11. July 24, 2012

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

Functional Programming. Pure Functional Languages

Extra Lecture #7: Defining Syntax

Administrative Stuff

Administrivia. Simple data types

Structure and Interpretation of Computer Programs

Scheme: Expressions & Procedures

Programming Principles

CMSC 201 Fall 2016 Lab 09 Advanced Debugging

CSE 341 Section 7. Ethan Shea Autumn Adapted from slides by Nicholas Shahan, Dan Grossman, Tam Dang, and Eric Mullen

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

Fall 2017 December 4, Scheme. Instructions

Documentation for LISP in BASIC

CS 340 Spring 2019 Midterm Exam

Sample Final Exam Questions

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

CS61A Discussion Notes: Week 11: The Metacircular Evaluator By Greg Krimer, with slight modifications by Phoebus Chen (using notes from Todd Segal)

Lazy Evaluation and Parameter Transfer

CSE341 Spring 2016, Final Examination June 6, 2016

CS125 : Introduction to Computer Science. Lecture Notes #4 Type Checking, Input/Output, and Programming Style

Random Testing in 321

Structure and Interpretation of Computer Programs

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

Discussion 4. Data Abstraction and Sequences

Warm-up! CS 3 Final Review. Predict the output. Predict the Output. Predict the output. Predict the output. What is your favorite color?

Project 5 - The Meta-Circular Evaluator

A Brief Introduction to Scheme (II)

Programming Languages

Fall 2017 December 4, 2017

Streams and Evalutation Strategies

CSE 374: Programming Concepts and Tools. Eric Mullen Spring 2017 Lecture 4: More Shell Scripts

Organization of Programming Languages CS3200/5200N. Lecture 11

CSE 413 Midterm, May 6, 2011 Sample Solution Page 1 of 8

Transcription:

CS 61A Macros & Streams Spring 2018 Discussion 9: April 11, 2018 1 Macros So far, we ve mostly explored similarities between the Python and Scheme languages. For example, the Scheme list data structure is a close analogue to the Python linked list. As another example, we saw how tail-call optimization allows us to write recursive Scheme functions that use a constant amount of space. This makes it feasible to translate iterative code from Python. On the other hand, macros are a Scheme feature that don t have a apparent Python equivalent. Like functions, macros are a useful tool for simplifying code via abstraction. But while functions typically operate on values like numbers and lists, macros have the option of transforming unevaluated code, leading to a whole new world of possibilities! As a reminder, most Scheme functions do not have side effects. One exception to this is print. Just like in Python, print doesn t return anything! With that in mind, let s consider an example where we want to repeat a piece of code twice. (print 'woof) A first attempt at this might be: scm> (print 1) 1 scm> (print 'hello) hello scm> (print '(yes this is dog)) (yes this is dog) scm> (define (twice f) (begin f f)) twice scm> (twice (print 'woof)) woof Remember that print doesn t return anything! So we would only see the first call to print in this case. The problem here is clear: we need to prevent the expression we want to double from evaluating, and then somehow call it twice. As an example of this, imagine if the problem were less constrained and we could surround our original expression in a define expression. In that case, we could use higher order functions to get what we want: scm> (define (speak) (print 'woof)) speak scm> (define (twice f) (begin (f) (f))) twice scm> (twice speak) woof woof But if the expression is given to us directly, there s no way to undo the execution and delay it for later!

2 Macros & Streams scm> (define (twice result) (begin (define (f) result) % This won't work! (f)(f))) twice scm> (twice (print 'woof)) woof Clearly, we need a special form, since we cannot evaluate our operand immediately. This is where we apply the define-macro special form. scm> (define-macro (twice f) (list 'begin f f)) twice This looks a bit like a function definition. twice is the name of the macro, and everything that follows in the same list is a required parameter. When we evaluate the macro form, we won t evaluate any parameters immediately. Instead, the body of the macro describes the final expression we want to evaluate, with the unevaluated parameters put in place! Recall that we want a final expression that looks like: (begin (print 'woof) (print 'woof)) Now, let f be the snippet of print code from earlier (not the result of evaluation, which is simply nothing) The expression: (list 'begin f f) Creates our desired expression, and then finally evaluates it. Note that if we used: '(begin f f) This wouldn t work, since f would stay as f and wouldn t be replaced with our print expression. However, this seems easier to do than calling list a bunch of times. Is there a way to get the best of both worlds? 1.1 Quasiquoting Recall that the quote special form prevents the Scheme interpreter from executing a following expression. You may have used it in the past to create lists without needing to call functions such as cons and list. However, you cannot create any lists that depend on the results of function evaluation due to the fact that quoting will surpress all evaluation. This is not the case with quasiquoting. At first glance, the quasiquote (which can be invoked with the backtick ` or the quasiquote special form) behaves exactly the same. However, using quasiquotes gives you the ability to unquote (which can be invoked with the the comma, or the unquote special form). This removes an expression from the quoted context, evaluates it, and places it back in. scm> (define a 1) a scm> '(cons a nil) (cons a nil) scm> `(cons a nil) (cons a nil) scm> `(cons,a nil) (cons 1 nil)

Macros & Streams 3 By combining quasiquotes and unquoting, we can often save ourselves a lot of trouble when building macro expressions. As one last example, we can create a quasiquoted version of our macro from earlier: (define-macro (twice f) `(begin,f,f)) Questions 1.1 Write a macro that takes an expression and a number n and repeats the expression n times. For example, (repeat-n expr 2) should behave the same as (twice expr). Complete the implementation below, making use of the replicate function. (define (replicate x n) (if (= n 0) nil (cons x (replicate x (- n 1))))) (define-macro (repeat-n expr n) scm> (repeat-n (print '(resistance is futile)) 4) (resistance is futile) (resistance is futile) (resistance is futile) (resistance is futile) 1.2 Write a macro that takes in two expressions and or s them together (applying shortcircuiting rules). However, do this without using the or special form. You may also assume the name v1 doesn t appear anywhere outside of our macro. Fill in the implementation below. (define-macro (or-macro expr1 expr2) `(let ((v1 )) (if ))) scm> (or-macro (print 'bork) (/ 1 0)) bork scm> (or-macro (= 1 0) (+ 1 2)) 3

4 Macros & Streams 1.3 Write a macro that takes in a call expression and strips out every other argument. The first argument is kept, the second is removed, and so on. You may find it helpful to write a helper function. (define-macro (prune-expr expr) scm> (prune-expr (+ 10)) 10 scm> (prune-expr (+ 10 100)) 10 scm> (prune-expr (+ 10 100 1000)) 1010 scm> (prune-expr (prune-expr (+ 10 100) 'garbage)) 10

Macros & Streams 5 2 Streams In Python, we can use iterators to represent infinite sequences (for example, the generator for all natural numbers). However, Scheme does not support iterators. Let s see what happens when we try to use a Scheme list to represent an infinite sequence of natural numbers: scm> (define (naturals n) (cons n (naturals (+ n 1)))) naturals scm> (naturals 0) Error: maximum recursion depth exceeded Because the second argument to cons is always evaluated, we cannot create an infinite sequence of integers using a Scheme list. Instead, our Scheme interpreter supports streams, which are lazy Scheme lists. The first element is represented explicitly, but the rest of the stream s elements are computed only when needed. Computing a value only when it s needed is also known as lazy evaluation. scm> (define (naturals n) (cons-stream n (naturals (+ n 1)))) naturals scm> (define nat (naturals 0)) nat scm> (car nat) 0 scm> (car (cdr-stream nat)) 1 scm> (car (cdr-stream (cdr-stream nat))) 2 We use the special form cons-stream to create a stream. Note that cons-stream is a special form, because the second operand (naturals (+ n 1))) is not evaluated when cons-stream is called. It s only evaluated when cdr-stream is used to inspect the rest of the stream. nil is the empty stream cons-stream creates a non-empty stream from an initial element and an expression to compute the rest of the stream car returns the first element of the stream cdr-stream computes and returns the rest of stream Streams are very similar to Scheme lists. The cdr of a Scheme list is either another Scheme list or nil; likewise, the cdr-stream of a stream is either a stream or nil. The difference is that the expression for the rest of the stream is computed the first time that cdr-stream is called, instead of when cons-stream is used. Subsequent calls to cdr-stream return this value without recomputing it. This allows us to

6 Macros & Streams efficiently work with infinite streams like the naturals example above. We can see this in action by using a non-pure function to compute the rest of the stream: scm> (define (compute-rest n)...> (print 'evaluating!)...> (cons-stream n nil)) compute-rest scm> (define s (cons-stream 0 (compute-rest 1))) s scm> (car (cdr-stream s)) evaluating! 1 scm> (car (cdr-stream s)) 1 Note that the symbol evaluating! called. is only printed the first time cdr-stream is Questions 2.1 What would Scheme display? scm> (define (has-even? s) (cond ((null? s) #f) ((even? (car s)) #t) (else (has-even? (cdr-stream s))))) has-even? scm> (define (f x) (* 3 x)) f scm> (define nums (cons-stream 1 (cons-stream (f 3) (cons-stream (f 5) nil)))) nums scm> nums scm> (cdr nums) scm> (cdr-stream nums) scm> (define (f x) (* 2 x)) f scm> (cdr-stream nums) scm> (has-even? nums)

Macros & Streams 7 2.2 Write a function range-stream which takes a start and end, and returns a stream that represents the integers between start and end - 1 (inclusive). (define (range-stream start end) (if ( ) nil (cons-stream ))) scm> (define s (range-stream 1 5)) s scm> (car (cdr-stream s)) 2 2.3 Write a function slice which takes in a stream s, a start, and an end. It should return a Scheme list that contains the elements of s between index start and end, not including end. If the stream ends before end, you can return nil. (define (slice s start end) scm> (slice nat 4 12) (4 5 6 7 8 9 10 11) 2.4 Since streams only evaluate the next element when they are needed, we can combine infinite streams together for interesting results! Use it to define a few of our favorite sequences. We ve defined the function combine-with for you below, as well as an example of how to use it to define the stream of even numbers. (define (combine-with f xs ys) (if (or (null? xs) (null? ys)) nil (cons-stream (f (car xs) (car ys)) (combine-with f (cdr-stream xs) (cdr-stream ys))))) scm> (define evens (combine-with + (naturals 0) (naturals 0))) evens scm> (slice evens 0 10) (0 2 4 6 8 10 12 14 16 18) For these questions, you may use the naturals stream in addition to combine-with. (Continued on the next page)

8 Macros & Streams i. (define factorials scm> (slice factorials 0 10) (1 1 2 6 24 120 720 5040 40320 362880) ii. (define fibs scm> (slice fibs 0 10) (0 1 1 2 3 5 8 13 21 34) iii. Write exp, which returns a stream where the nth term represents the degree-n polynomial expantion for e x, which is n i=0 xi /i!. You may use factorials in addition to combine-with and naturals in your solution. (define (exp x) scm> (slice (exp 2) 0 5) (1 3 5 6.333333333 7 7.266666667)