An Explicit-Continuation Metacircular Evaluator

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

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

Building a system for symbolic differentiation

Discussion 12 The MCE (solutions)

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

CSc 520 Principles of Programming Languages

Building a system for symbolic differentiation

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

Using Symbols in Expressions (1) evaluate sub-expressions... Number. ( ) machine code to add

Functional Programming. Pure Functional Programming

A Brief Introduction to Scheme (II)

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

CS61A Midterm 2 Review (v1.1)

Introduction to Scheme

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

6.001: Structure and Interpretation of Computer Programs

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

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

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

Simplifying Logical Formulas

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

Vectors in Scheme. Data Structures in Scheme

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

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

CS 314 Principles of Programming Languages. Lecture 16

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

(scheme-1) has lambda but NOT define

University of Massachusetts Lowell

Project 2: Scheme Interpreter

Notes on Higher Order Programming in Scheme. by Alexander Stepanov

LECTURE 16. Functional Programming

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

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

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

1.3. Conditional expressions To express case distinctions like

6.945 Adventures in Advanced Symbolic Programming

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

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

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

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

CS 275 Name Final Exam Solutions December 16, 2016

Functional Programming. Pure Functional Languages

Essentials of Programming Languages Language

CS 314 Principles of Programming Languages

Essentials of Programming Languages Language

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

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


CS 360 Programming Languages Interpreters

Chapter 1. Fundamentals of Higher Order Programming

Functional Languages. Hwansoo Han

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

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

Sample midterm 1 #1. Problem 1 (What will Scheme print?).

SCHEME AND CALCULATOR 5b

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

Sample Final Exam Questions

Functional Programming. Pure Functional Languages

An Introduction to Scheme

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

Evaluating Scheme Expressions

CSC 533: Programming Languages. Spring 2015

Lexical vs. Dynamic Scope

Announcement. Overview. LISP: A Quick Overview. Outline of Writing and Running Lisp.

Programming Languages

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

Data abstraction, revisited

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

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

CS 342 Lecture 8 Data Abstraction By: Hridesh Rajan

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

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

Lecture Notes on Lisp A Brief Introduction

Turtles All The Way Down

An Explicit Continuation Evaluator for Scheme

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

How to Design Programs Languages

From Syntactic Sugar to the Syntactic Meth Lab:

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

Introduction to Functional Programming in Racket. CS 550 Programming Languages Jeremy Johnson

Lecture #24: Programming Languages and Programs

6.001 recitation 3/21/07

Fall Semester, Lecture Notes { November 12, Variations on a Scheme Nondeterministic evaluation

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

CSE341 Spring 2017, Final Examination June 8, 2017

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

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

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

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

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Lists in Lisp and Scheme

Scheme Quick Reference

Functional Programming

4.2 Variations on a Scheme -- Lazy Evaluation

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

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

ALISP interpreter in Awk

Fall 2017 December 4, 2017

Transcription:

Computer Science (1)21b (Spring Term, 2018) Structure and Interpretation of Computer Programs An Explicit-Continuation Metacircular Evaluator The vanilla metacircular evaluator gives a lot of information about ironments, but not much information about control when the evaluation of a subexpression returns a value, what happens next? In the explicit-continuation evaluator given here, a new parameter to the eval procedure called a continuation is a procedure that tells exactly what to do next. The evaluation of every expression takes place in the context of some continuation. This continuation is thus a sort of function that takes a value produced by a computation, and then does something with the value. For example, in the read-eval-print loop, at the point of evaluation, the continuation is given value v, print it, then go through the loop again. Said otherwise: Every time a procedure is called, it is for two reasons. First: we have an input that needs feeding in. Second: we have a need to do something with what the procedure returns as a value. What is to do with what comes out of the procedure call? That s what the continuation describes. Since lambda is how we describe functions (procedures) in Scheme, let s use them to describe continuations. Simplify the above continuation to (lambda (v) v) just return the value. When evaluating the recursive call (fact 2) in the evaluation of (fact 4), the continuation is then (effectively) (lambda (v) (* 4 (* 3 v))). Here, in fact, is an explicit-control version of factorial, analogous to the explicit-control evaluator. First, we ll use these: (define (compose f g) (lambda (v) (f (g v)))) (define (mult m) (lambda (v) (* m v))) (define (I v) v) Now, for the code of factorial with an explicit continuation: (define (factorial n k) (if (= n 0) (k 1) (factorial (- n 1) (compose k (mult n))))) 1

The second argument (compose k (mult n)) says what to do with the computation of (n 1)!. Notice that the recursive call is tail recursive, and thus creates an iterative process no extra work accumulates outside the recursive call: the procedure maintains all releavant data in its two arguments. 1. To compute factorial of 3, we evaluate: (factorial 3 I). How does this computation take place in the substitution model? We have: (define (factorial n k) (if (= n 0) (k 1) (factorial (- n 1) (compose k (mult n))))) (factorial 3 I) (factorial 2 (compose I (mult 3))) (factorial 1 (compose (compose I (mult 3)) (mult 2))) (factorial 0 (compose (compose (compose I (mult 3)) (mult 2)) (mult 1))) ((compose (compose (compose I (mult 3)) (mult 2)) (mult 1)) 1)... (I ((mult 3) ((mult 2) ((mult 1) 1))))... (* 3 (* 2 (* 1 1))) 6 There s an easy induction proof (on m) that (factorial m K) = (K m!). The basis is easy: when m = 0, the substitution model tells us (factorial 0 K) = (K 1) = (K 0!) and when m = n + 1, we have (factorial n + 1 K) = (factorial n (compose K (mult n + 1))) by the substitution model = ((compose K (mult n + 1)) n!) by the inductive hypothesis = (K (n + 1)!). We are going to design a metacircular evaluator that has an explicit continuation every expression is evaluated in the context of an ironment and a continuation. In this initial presentation, we simplify the language we re evaluation to make the evaluator easier to read. 1 Of course, the fiction of constant space is evident, since the size of these two arguments is growing. 2

Simplifications: Definitions are written (define name body ); all procedures have only one argument. Primitive procedures have been curried: we write ((* 3) 5) instead of (* 3 5). For example: (define fact (lambda (n) (if ((= n) 0) 1 ((* n) (fact ((- n) 1)))))) The existence of the explicit control lets us introduce two (non Scheme standard) constructs: enter and exit. Here s an example of what they do: (try (enter ((+ 5) (exit 3)))) ;Value: 3 ((lambda (x) (lambda (y) ((* ((+ x) y)) (enter ((- x) (exit y))))) 10) 2) ;Value: 24 (10 substituted for x, then 2 for y.) Constructs like enter and exit are useful when designing and implementing error handlers for systems where we need to jump out of a control context, for example: (define (lookup-variable v -names) (if (null? -names) (error "Name not in list") (if (eq? v (car -names)) 0 (1+ (lookup-variable v (cdr -names)))))) (How would you design an error handler for your metacircular evaluator that bumps the user up to the read-eval-print loop of the evaluator, and not the underlying Scheme system?) 3

(define (eval exp cont) (cond ((constant? exp) (cont exp)) ((variable? exp) (cont (lookup exp))) ((define? exp) (let ((new- (extend (def-name exp) *UNEVALUATED* ))) (eval (def-body exp) new- (lambda (v) (set-cdr! (car new-) v) (cont (cons *define* new-)))))) ((if? exp) (eval (predicate exp) (lambda (p) (eval (if p (then-part exp) (else-part exp)) cont)))) ((enter? exp) (eval (enter-body exp) (extend *exit-continuation* cont ) cont)) ((exit? exp) (eval (exit-body exp) (lookup *exit-continuation*))) 4

In this simple language, all procedures have one argument. A lambda-expression is then interpreted as a lambda-expression in the underlying Scheme system with two parameters x and k: the procedure implements a function which needs to know two things its input (named by x) and what to do with its output (named by continuation k). The continuation cont is applied to the procedure when it is (statically) defined, answering the question what do we do with the procedure when it is created? The continuation k is applied to the value returned by the procedure body when it is (dynamically) used. ((lambda? exp) (cont (lambda (x k) (eval (body exp) (extend (binder exp) x ) k)))) The above definition makes sense in the context of the dual definition of function application. The function is evaluated with the continuation of evaluating the argument; the continuation for the latter is to apply the evaluated function to the evaluated argument with the current continuation cont so we know what to do with the answer returned by the function application. ((application? exp) (eval (function-of exp) (lambda (f) (eval (argument-of exp) (lambda (a) (f a cont)))))) 5

(else ;; it s a sequence of stuff! (let ((first (first-exp exp)) (rest (rest-exps exp))) (eval first (lambda (a) (eval rest (if ((begins-with *define*) a) (cdr a) ) cont))))))) Initial continuation and global ironment (define (initial-continuation x) x) (define (extend var val ) (cons (cons var val) )) (define (lookup var) (cond ((null? ) (error "Unbound variable")) ((eq? (caar ) var) (cdar )) (else (lookup (cdr ) var)))) (define (unop op) (lambda (x k) (k (op x)))) (define (binop op) (lambda (x k) (k (lambda (y kk) (kk (op x y)))))) 6

(define (terop op) (lambda (x k) (k (lambda (y kk) (kk (lambda (z kkk) (kkk (op x y z)))))))) (define initial-global-ironment (extend cons (binop cons) (extend - (binop -) (extend * (binop *) (extend + (binop +) (extend = (binop =) (extend < (binop <) (extend 1+ (unop 1+) ())))))))) (define (try exp) (eval exp initial-global-ironment initial-continuation)) 7

Constructors, destructors, other silly stuff (define constant? integer?) (define (variable? v) (not (pair? v))) (define (begins-with atom) (lambda (exp) (if (pair? exp) (equal? (car exp) atom) #f))) (define lambda? (begins-with lambda)) (define binder caadr) (define body caddr) (define define? (begins-with define)) (define define-of car) (define (rest-of exp) (if (null? (cddr exp)) (cadr exp) (cdr exp))) (define def-name cadr) (define (def-body exp) (if (null? (cdddr exp)) (caddr exp) (cddr exp))) (define if? (begins-with if)) (define predicate cadr) (define else-part cadddr) (define then-part caddr) (define sequence? (begins-with begin)) (define first-exp car) (define (rest-exps exp) (let ((r (cdr exp))) (if (pair? r) (if (null? (cdr r)) (car r) r) r))) (define enter? (begins-with enter)) (define exit? (begins-with exit)) (define enter-body cadr) (define exit-body cadr) (define (application? exp) (if (pair? exp) (not ((begins-with define) (car exp))) #f)) (define function-of car) (define argument-of cadr) 8