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

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

INTERPRETERS AND TAIL CALLS 9

EXCEPTIONS, CALCULATOR 10

SCHEME AND CALCULATOR 5b

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

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

CALCULATOR Calculator COMPUTER SCIENCE 61A. July 24, 2014

TAIL CALLS, ITERATORS, AND GENERATORS 11

TAIL RECURSION, SCOPE, AND PROJECT 4 11

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

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

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

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

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

INTERPRETATION AND SCHEME LISTS 12

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

INTERPRETATION AND SCHEME LISTS 12

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

MEMOIZATION, RECURSIVE DATA, AND SETS

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

Structure and Interpretation of Computer Programs

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

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

Resources matter. Orders of Growth of Processes. R(n)= (n 2 ) Orders of growth of processes. Partial trace for (ifact 4) Partial trace for (fact 4)

ITERATORS AND STREAMS 9

CSCC24 Functional Programming Scheme Part 2

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

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

61A Lecture 26. Monday, October 31

Functional Programming. Pure Functional Programming

Fall Semester, The Metacircular Evaluator. Today we shift perspective from that of a user of computer langugaes to that of a designer of

RLISTS AND THE ENVIRONMENT MODEL 9

ENVIRONMENT DIAGRAMS AND RECURSION 2

Structure and Interpretation of Computer Programs Spring 2014 Final (with corrections)

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

An Explicit-Continuation Metacircular Evaluator

CS61A Notes Week 13: Interpreters

An introduction to Scheme

Below are example solutions for each of the questions. These are not the only possible answers, but they are the most common ones.

Building a system for symbolic differentiation

Project 2: Scheme Interpreter

Building a system for symbolic differentiation

CS61A Midterm 2 Review (v1.1)

Sample Final Exam Questions

LINKED LISTS AND MIDTERM REVIEW 6

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

CSCI 121: Recursive Functions & Procedures

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

An Explicit Continuation Evaluator for Scheme

Chapter 1. Fundamentals of Higher Order Programming

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

Structure and Interpretation of Computer Programs

;; definition of function, fun, that adds 7 to the input (define fun (lambda (x) (+ x 7)))

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

by the evening of Tuesday, Feb 6

Discussion 12 The MCE (solutions)


STRUCTURE AND INTERPRETATION COMPUTER PROGRAMS >>> COMPUTER SCIENCE IN THE NEWS. CS61A Lecture 23 Py TODAY REVIEW: INTERPRETATION 7/26/2012 READ PRINT

Homework 1. Reading. Problems. Handout 3 CSCI 334: Spring, 2012

4.2 Variations on a Scheme -- Lazy Evaluation

STRUCTURE AND INTERPRETATION COMPUTER PROGRAMS COMPUTER SCIENCE IN THE NEWS. CS61A Lecture 23 Py TODAY 7/26/2012

Homework 1. Notes. What To Turn In. Unix Accounts. Reading. Handout 3 CSCI 334: Spring, 2017

CS116 - Module 5 - Accumulative Recursion

Code example: sfact SICP Explicit-control evaluator. Example register machine: instructions. Goal: a tail-recursive evaluator.

A Second Look At ML. Chapter Seven Modern Programming Languages, 2nd ed. 1

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

6.001 Notes: Section 4.1

Functional abstraction. What is abstraction? Eating apples. Readings: HtDP, sections Language level: Intermediate Student With Lambda

Functional abstraction

61A LECTURE 15 MEMOIZATION, RECURSIVE DATA, SETS

CS61A Lecture 23 Py. Jom Magrotker UC Berkeley EECS July 26, 2012

CS450 - Structure of Higher Level Languages

UNIVERSITY OF TORONTO Faculty of Arts and Science. Midterm Sample Solutions CSC324H1 Duration: 50 minutes Instructor(s): David Liu.

# track total function calls using a global variable global fibcallcounter fibcallcounter +=1

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

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

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

Algorithm Design and Recursion. Search and Sort Algorithms

Lambda Calculus and Lambda notation in Lisp II. Based on Prof. Gotshalks notes on Lambda Calculus and Chapter 9 in Wilensky.

More About Recursive Data Types

MetacircularScheme! (a variant of lisp)

Module 8: Local and functional abstraction

CS115 INTRODUCTION TO COMPUTER SCIENCE 1. Additional Notes Module 5

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

April 2 to April 4, 2018

Documentation for LISP in BASIC

Introduction to Functional Programming

Structure and Interpretation of Computer Programs

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

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

Structure and Interpretation of Computer Programs Summer 2015 Midterm 2

Parsing Scheme (+ (* 2 3) 1) * 1

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

Public-Service Announcement

;;; Determines if e is a primitive by looking it up in the primitive environment. ;;; Define indentation and output routines for the output for

6.001 Notes: Section 15.1

Week - 03 Lecture - 18 Recursion. For the last lecture of this week, we will look at recursive functions. (Refer Slide Time: 00:05)

CS61C Machine Structures. Lecture 12 - MIPS Procedures II & Logical Ops. 2/13/2006 John Wawrzynek. www-inst.eecs.berkeley.

STREAMS, ITERATORS, AND BINARY TREES 10

Lecture #24: Programming Languages and Programs

Transcription:

INTERPRETERS 8 COMPUTER SCIENCE 61A November 3, 2016 1 Calculator We are beginning to dive into the realm of interpreting computer programs that is, writing programs that understand other programs. In order to do so, we ll have to examine programming languages in-depth. The Calculator language, a subset of Scheme, was the first of these examples. In today s discussion, we ll be extending Calculator with variables and user-defined functions. The Calculator language is a Scheme-syntax language that currently includes only the four basic arithmetic operations: +,,, and /. These operations can be nested and can take varying numbers of arguments. Here s a few examples of Calculator in action: calc> (+ 2 2) 4 calc> (- 5) -5 calc> (* (+ 1 2) (+ 2 3)) 15 Our goal now is to write an interpreter for this language, and extend its functionality to variables and user-defined functions. The job of an interpreter is to evaluate expressions. So, let s talk about expressions. A Calculator expression is just like a Scheme list. To represent Scheme lists in Python, we use Pair objects. For example, the list (+ 1 2) is represented as Pair( +, Pair(1,

DISCUSSION 8: INTERPRETERS Page 2 Pair(2, nil))). The Pair class is similar to the Scheme procedure cons, which would represent the same list as (cons + (cons 1 (cons 2 nil))). Pair is very similar to Link, the class we developed for representing linked lists. In addition to Pair objects, we include a nil object to represent the empty list. Pair instances have methods: 1. len, which returns the length of the list. 2. getitem, which allows indexing into the pair. 3. map, which applies a function, fn, to all of the elements in the list. nil has the methods len, getitem, and map. Here s an implementation of what we described: class nil: """Represents the special empty pair nil in Scheme.""" def repr (self): return 'nil' def len (self): return 0 def getitem (self, i): raise IndexError('Index out of range') def map(self, fn): return nil nil = nil() # this hides the nil class *forever* class Pair: """Represents the built-in pair data structure in Scheme.""" def init (self, first, second): self.first = first self.second = second def repr (self): return 'Pair({}, {})'.format(self.first, self.second) def len (self): return 1 + len(self.second) def getitem (self, i): if i == 0: return self.first return self.second[i-1] def map(self, fn): return Pair(fn(self.first), self.second.map(fn))

DISCUSSION 8: INTERPRETERS Page 3 1.1 Questions 1. Translate the following Calculator expressions into calls to the Pair constructor. > (+ 1 2 (- 3 4)) > (+ 1 (* 2 3) 4) 2. Translate the following Python representations of Calculator expressions into the proper Scheme syntax: >>> Pair('+', Pair(1, Pair(2, Pair(3, Pair(4, nil))))) >>> Pair('+', Pair(1, Pair(Pair('*', Pair(2, Pair(3, nil))), nil))) 2 Evaluation Evaluation discovers the form of an expression and executes a corresponding evaluation rule. We ll go over two such expressions now: 1. Primitive expressions are evaluated directly. For example, the numbers 3.14 and 165 just evaluate to themselves, and the string + evaluates to the calc add function. 2. Call expressions are evaluated in the same way you ve been doing them all semester: (1) Evaluate the operator. (2) Evaluate the operands from left to right. (3) Apply the operator to the operands.

DISCUSSION 8: INTERPRETERS Page 4 Here s calc eval: def calc_eval(exp): """Evaluates a Calculator expression represented as a Pair. """ if isinstance(exp, Pair): return calc_apply(calc_eval(exp.first), list(exp.second.map(calc_eval))) elif exp in OPERATORS: return OPERATORS[exp] else: # Primitive expression return exp And here s calc apply: def calc_apply(op, args): """Applies an operator to a Pair of arguments.""" return op(*args) 2.1 Questions 1. Suppose we typed each of the following expressions into the Calculator interpreter. How many calls to calc eval would they each generate? How many calls to calc apply? > (+ 2 4 6 8) > (+ 2 (* 4 (- 6 8))) 2. Alyssa P. Hacker and Ben Bitdiddle are also tasked with implementing the and operator, as in (and (= 1 2) (< 3 4)). Ben says this is easy: they just have to follow the same process as in implementing * and /. Alyssa is not so sure. Who s right?

DISCUSSION 8: INTERPRETERS Page 5 3. Now that you ve had a chance to think about it, you decide to try implementing and yourself. You may assume the conditional operators (e.g. <, >, =, etc) have already been implemented for you. def calc_eval(exp): def eval_and(operands):

DISCUSSION 8: INTERPRETERS Page 6 3 Tail-Call Optimization Scheme implements tail-call optimization, which allows programmers to write recursive functions that use a constant amount of space. A tail call occurs when a function calls another function as its last action of the current frame. Because in this case Scheme won t make any further variable lookups in the frame, the frame is no longer needed, and we can remove it from memory. In other words, if this is the last thing you are going to do in a function call, we can reuse the current frame instead of making a new frame. Consider this version of factorial that does not use tail calls: (define (fact n) (if (= n 0) 1 (* n (fact (- n 1))))) The recursive call occurs in the last line, but it is not the last expression evaluated. After calling (fact (- n 1)), the function still needs to multiply that result with n. The final expression that is evaluated is a call to the multiplication function, not fact itself. Therefore, the recursive call is not a tail call. However, we can rewrite this function using a helper function that remembers the temporary product that we have calculated so far in each recursive step. (define (fact n) (define (fact-tail n result) (if (= n 0) result (fact-tail (- n 1) (* n result)))) (fact-tail n 1)) fact-tail makes a single recursive call to fact-tail that is the last expression to be evaluated, so it is a tail call. Therefore, fact-tail is a tail recursive process. Tail recursive processes can take a constant amount of memory because each recursive call frame does not need to be saved. Our original implementation of fact required the program to keep each frame open because the last expression multiplies the recursive result with n. Therefore, at each frame, we need to remember the current value of n. In contrast, the tail recursive fact-tail does not require the interpreter to remember the values for n or result in each frame. Instead, we can just update the value of n and result of the current frame! Therefore, we can carry out the calculation using only enough memory for a single frame. 3.1 Identifying tail calls A function call is a tail call if it is in a tail context (but a tail call might not be a recursive tail call as seen above in the first fact definition). We consider the following to be tail contexts:

DISCUSSION 8: INTERPRETERS Page 7 the last sub-expression in a lambda s body the second or third sub-expression in an if form any of the non-predicate sub-expressions in a cond form the last sub-expression in an and or an or form the last sub-expression in a begin s body Before we jump into questions, a quick tip for defining tail recursive functions is to use helper functions. A helper function should have all the arguments from the parent function, plus additional arguments like total or counter or result. 1. For each of the following functions, identify whether it contains a recursive call in a tail context. Also indicate if it uses a constant number of frames. (define (question-a x) (if (= x 0) 0 (+ x (question-a (- x 1))))) (define (question-b x y) (if (= x 0) y (question-b (- x 1) (+ y x)))) (define (question-c x y) (if (> x y) (question-c (- y 1) x) (question-c (+ x 10) y))) (define (question-d n) (if (question-d n) (question-d (- n 1)) (question-d (+ n 10)))) 2. Write a tail recursive function that returns the nth fibonacci number. We define fib(0) = 0 and fib(1) = 1. (define (fib n)

DISCUSSION 8: INTERPRETERS Page 8 3. Write a tail recursive function, reverse, that takes in a Scheme list and returns a reversed copy. (define (reverse lst) 4. Write a tail recursive function, insert, that takes in a number and a sorted list. The function returns a sorted copy with the number inserted in the correct position. (define (insert n lst)