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

Similar documents
Scheme in Scheme: The Metacircular Evaluator Eval and Apply

An Explicit-Continuation Metacircular Evaluator

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

Functional Programming. Pure Functional Programming

Discussion 12 The MCE (solutions)

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

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

CS 275 Name Final Exam Solutions December 16, 2016

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

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

Turtles All The Way Down

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

Building a system for symbolic differentiation

User-defined Functions. Conditional Expressions in Scheme

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

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

6.001, Spring Semester, 1998, Final Exam Solutions Your Name: 2 Part c: The procedure eval-until: (define (eval-until exp env) (let ((return (eval-seq

Functional Programming - 2. Higher Order Functions

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

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

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

A Brief Introduction to Scheme (II)

Functional Programming. Pure Functional Languages

Sample Final Exam Questions

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

CONCEPTS OF PROGRAMMING LANGUAGES Solutions for Mid-Term Examination

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

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

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

Functional Programming. Pure Functional Languages

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

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

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

CS 314 Principles of Programming Languages. Lecture 16

Lexical vs. Dynamic Scope

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

More Scheme CS 331. Quiz. 4. What is the length of the list (()()()())? Which element does (car (cdr (x y z))) extract from the list?

CS 314 Principles of Programming Languages

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

Building a system for symbolic differentiation

From Syntactic Sugar to the Syntactic Meth Lab:

Comp 311: Sample Midterm Examination

CSE413 Midterm. Question Max Points Total 100

Project 2: Scheme Interpreter

CSc 520 Principles of Programming Languages

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

An Introduction to Scheme

An Explicit Continuation Evaluator for Scheme

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

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

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

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

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

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

Programming Languages

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

CS450 - Structure of Higher Level Languages

CS 314 Principles of Programming Languages

C311 Lab #3 Representation Independence: Representation Independent Interpreters

Box-and-arrow Diagrams

11/6/17. Functional programming. FP Foundations, Scheme (2) LISP Data Types. LISP Data Types. LISP Data Types. Scheme. LISP: John McCarthy 1958 MIT

CSSE 304 Assignment #13 (interpreter milestone #1) Updated for Fall, 2018

CS 314 Principles of Programming Languages

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

CS61A Midterm 2 Review (v1.1)

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

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

6.001, Spring Semester, 1998, Final Exam Your Name: 2 Question 1 (12 points): Each of the parts below should be treated as independent. For each part,

First-class continuations. call/cc, stack-passing CEK machines

bindings (review) Topic 18 Environment Model of Evaluation bindings (review) frames (review) frames (review) frames (review) x: 10 y: #f x: 10

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

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

Repetition Through Recursion

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

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

FP Foundations, Scheme

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

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

Lisp. Versions of LISP

Symbolic Programming. Dr. Zoran Duric () Symbolic Programming 1/ 89 August 28, / 89

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

Building up a language SICP Variations on a Scheme. Meval. The Core Evaluator. Eval. Apply. 2. syntax procedures. 1.

Principles of Programming Languages Topic: Scope and Memory Professor Louis Steinberg Fall 2004

Scheme Quick Reference

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.

Documentation for LISP in BASIC

Konzepte von Programmiersprachen

CS 360 Programming Languages Interpreters

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Scheme Quick Reference

CSE 341: Programming Languages

Scheme Tutorial. Introduction. The Structure of Scheme Programs. Syntax

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

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

Administrivia. Simple data types

Lecture 3: Expressions

Organization of Programming Languages CS3200/5200N. Lecture 11

This exam is worth 30 points, or 18.75% of your total course grade. The exam contains

6.034 Artificial Intelligence February 9, 2007 Recitation # 1. (b) Draw the tree structure corresponding to the following list.

CSE Programming Languages Final exam - Winter Answer Key

Transcription:

Computer Science 21b (Spring Term, 2015) Structure and Interpretation of Computer Programs Lexical addressing The difference between a interpreter and a compiler is really two points on a spectrum of possible computations that occur either now (compile time) or later (run time). The mechanics of variable lookup is a case in point. When the metacircular evaluator needs to find the value of a variable x, it searches through the entire environment. Our Scheme evaluator uses static binding: every user-defined procedure has a fixed place where, no matter when and where the procedure is used, all frames (created by procedure application) are attached. It turns out that without running the program, we can figure out where in the environment every binding will occur, even if we cannot know what value will occur in that binding. Knowing where can speed up variable lookup at runtime. If variable x occurs four frames up, fifth variable in the frame, we don t need to search the frames in between: we march up the list of frames (using cdr), enter the frame, march over four bindings, and voilà. Even if the environment is just one long list of bindings, lookup gets faster we don t need to check each binding. 1

For simplification, all procedure take exactly one argument then the compile-time environment is just a list of variable names. (Why don t we need frames?) (compile 5 ()) ;Value: 5 (compile x (u v w x y)) ;Value: (var 3) (The variable x is three steps from the front of the list.) (compile v ()) ;Value: (var v) (Since v doesn t appear in the compile-time environment, we ll leave it unchanged.) (compile (lambda (x) x) (u v w x y)) ;Value: (lambda (var 0)) (When the body of the procedure is evaluated, the compile-time environment will be x u v w x y.) (compile (lambda (x) (x w)) (u v w x y)) ;Value: (lambda ((var 0) (var 3))) (compile (lambda (x) (lambda (y) (x y))) ()) ;Value: (lambda (lambda ((var 1) (var 0)))) (compile (if (zero? n) 0 y) (n y)) ;Value: (if ((var zero?) (var 0)) 0 (var 1)) (compile (enter ((+ 5) (exit z))) (x y z u v w)) ;Value: (enter (((var +) 5) (exit (var 3)))) 2

Recursion poses a new problem. Consider this: (define (even? n) (if (= n 0) #t (odd? (- n 1)))) (define (odd? n) (if (= n 0) #f (even? (- n 1)))) Each procedure above calls the other (coroutining). When we compile each, we need to generate lexical addresses of the calls to even? and odd?. But we re now compiling one at a time so if we compile even? first, where s the lexical address for odd?? (This isn t a problem in the earlier evaluators, because there s no evaluation inside a lambda but now, there is computation inside a lambda.) The solution is letrec, where in computing lexical addresses, we put all the names in env-names (the compile-time environment) first, and compile each body in the letrec in that new environment. (compile (letrec ((inc (lambda (x) (1+ x)))) (inc 10)) ()) ;Value: (letrec ((inc (lambda ((var 1+) (var 0))))) ((var 0) 10)) (When the body of a letrec (a recursive let) is evaluated, the bindings are already in the environment.) (compile (letrec ((square (lambda (x) ((* x) x))) (decrease (lambda (y) ((- y) 1)))) (decrease (square 5))) ()) ;Value: (letrec ((square (lambda (((var *) (var 0)) (var 0)))) (decrease (lambda (((var -) (var 0)) 1)))) ((var 1) ((var 0) 5))) ;No value 3

(compile (letrec ((even? (lambda (n) (if (zero? n) true (odd? ((- n) 1))))) (odd? (lambda (n) (if (zero? n) false (even? ((- n) 1)))))) (odd? 10)) initial-names) ;Value: (letrec ((even? (lambda (if ((var 8) (var 0)) (var 9) ((var 2) (((var 11) (var 0)) 1))))) (odd? (lambda (if ((var 8) (var 0)) (var 10) ((var 1) (((var 11) (var 0)) 1)))))) ((var 1) 10)) initial-names ;Value: (cons car cdr null? pair? zero? true false - * + = < 1+) (compile (letrec ((square (lambda (x) ((* x) x))) (decrease (lambda (y) ((- y) 1)))) (decrease (square 5))) initial-names) ;Value: (letrec ((square (lambda (((var 12) (var 0)) (var 0)))) (decrease (lambda (((var 11) (var 0)) 1)))) ((var 1) ((var 0) 5))) ;No value 4

(define (compile exp env-names) (cond ((constant? exp) exp) ((variable? exp) (list var (lookup-variable exp env-names))) ((letrec? exp) (compile-letrec (letrec-vars exp) (letrec-vals exp) (letrec-body exp) env-names)) ((lambda? exp) (list lambda (compile (body exp) (append (binders exp) env-names)))) ((if? exp) (cons if (compile-list (cdr exp) env-names))) ((sequence? exp) (cons begin (compile-list (cdr exp) env-names))) ((enter? exp) (cons enter (compile-list (cdr exp) (cons *EXIT* env-names)))) ((exit? exp) (cons exit (compile-list (cdr exp) env-names))) (else ; it s an application! (compile-list exp env-names)))) (define (compile-list exp env-names) (map (lambda (e) (compile e env-names)) exp)) 5

(define (compile-letrec vars vals body env-names) (let ((new-env-names (append vars env-names))) (let ((compiled-vals (map (lambda (val) (compile val new-env-names)) vals)) (body-code (compile body new-env-names))) (list letrec (zip-together vars compiled-vals) body-code)))) (define (zip-together vars vals) (if (null? vars) () (cons (cons (car vars) (list (car vals))) (zip-together (cdr vars) (cdr vals))))) (define (lookup-variable v env-names) (if (null? env-names) v (if (eq? v (car env-names)) 0 (let ((a (lookup-variable v (cdr env-names)))) (if (number? a) (1+ a) a))))) (define initial-names (cons car cdr null? pair? zero? true false - * + = < 1+)) 6

Notice the weird coding of lookup-variable why? (define (lookup-variable v env-names) (if (null? env-names) v (if (eq? v (car env-names)) 0 (let ((a (lookup-variable v (cdr env-names)))) (if (number? a) (1+ a) a))))) Here is something better but we need enter and exit in the underlying Scheme system! (define (lookup-variable v env-names) (define (loop names) (if (null? names) (exit v) (if (eq? v (car names)) 0 (1+ (loop (cdr names)))))) (enter (loop env-names))) 7