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

Similar documents
Scheme Quick Reference

Scheme Quick Reference

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

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

(scheme-1) has lambda but NOT define

CS61A Midterm 2 Review (v1.1)

Functional Programming. Pure Functional Programming

Project 2: Scheme Interpreter

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

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

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

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

Functional Programming. Pure Functional Languages

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

Functional Programming. Pure Functional Languages

CS 275 Name Final Exam Solutions December 16, 2016

CS 314 Principles of Programming Languages

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

A Brief Introduction to Scheme (II)

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

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

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

Introduction to Scheme

CSc 520 Principles of Programming Languages

Scheme in Scheme: The Metacircular Evaluator Eval and Apply

COP4020 Programming Languages. Functional Programming Prof. Robert van Engelen

CS 314 Principles of Programming Languages

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

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

An Explicit-Continuation Metacircular Evaluator

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?

Comp 311: Sample Midterm Examination

From Syntactic Sugar to the Syntactic Meth Lab:

Overview. CS301 Session 3. Problem set 1. Thinking recursively

CS 314 Principles of Programming Languages

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

LECTURE 16. Functional Programming

Building a system for symbolic differentiation

Building a system for symbolic differentiation

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

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

CSc 520. Principles of Programming Languages 7: Scheme List Processing

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

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

Documentation for LISP in BASIC

User-defined Functions. Conditional Expressions in Scheme

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

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


CSc 520 Principles of Programming Languages. Examining Lists. Constructing Lists... 7: Scheme List Processing

Essentials of Programming Languages Language

Essentials of Programming Languages Language

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

April 2 to April 4, 2018

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

An Introduction to Scheme

Sample Final Exam Questions

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

Evaluating Scheme Expressions

CS 360 Programming Languages Interpreters

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

Scheme as implemented by Racket

CS 314 Principles of Programming Languages. Lecture 16

CS450 - Structure of Higher Level Languages

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

CSE 341 Lecture 16. More Scheme: lists; helpers; let/let*; higher-order functions; lambdas

Principles of Programming Languages

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

CS 342 Lecture 7 Syntax Abstraction By: Hridesh Rajan

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

SCHEME AND CALCULATOR 5b

Lecture 3: Expressions

CSC 533: Programming Languages. Spring 2015

How to Design Programs Languages

(Func&onal (Programming (in (Scheme)))) Jianguo Lu

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

CSC324 Functional Programming Efficiency Issues, Parameter Lists

Discussion 12 The MCE (solutions)

Quicksort. Alternative Strategies for Dividing Lists. Fundamentals of Computer Science I (CS F)

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

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

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

Lisp. Versions of LISP

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

6.821 Programming Languages Handout Fall MASSACHVSETTS INSTITVTE OF TECHNOLOGY Department of Electrical Engineering and Compvter Science

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

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

Lexical vs. Dynamic Scope

Turtles All The Way Down

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

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

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

6.945 Adventures in Advanced Symbolic Programming

Functional Programming - 2. Higher Order Functions

INTRODUCTION TO SCHEME

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

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

CSE 341 Section Handout #6 Cheat Sheet

Scheme: Strings Scheme: I/O

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

Transcription:

Page 1/11 (require (lib "trace")) Allow tracing to be turned on and off (define tracing #f) Define a string to hold the error messages created during syntax checking (define error msg ""); Used for fancy error messages (define type ""); (define set error message (lambda (message) (set! error msg message))) Environment related function (define make new environment (lambda (bindings old env) (cons bindings old env))) (define lookup in environment (lambda (name env trace?) (if (eq? env null) #f (if trace? (output (format "Looking for ~a in ~a" name (pretty environment env)) # t #t)) (let ((pair (assv name (car env)))) pair (lookup in environment name (cdr env) trace?))))))) (define set in environment (lambda (name env value trace?) (if (eq? env null) #f (if trace? (output (format "Looking for ~a in ~a" name (pretty environment env)) # t #t)) (let ((pair (assv name (car env)))) (set cdr! pair value) (output (format "Setting ~a to ~a!" name value) #t #t) #t) (set in environment name (cdr env) value trace?))))))) (define pretty environment (lambda (env) (list (map (lambda (n v) (list n := v)) (map car (car env)) (map (lambda (x) (if (list? x) (list λ (cadr x)...) x)) (map cdr (car env)))) > parent))) Define a list of primitives (define prim (cons (list (cons + +) (cons ) (cons / /) (cons * *) (cons = =) (cons > >) (cons < <)) null)) is primitive? Determines if e is a primitive by looking it up in the primitive environment prim (define is primitive? (lambda (e) (assv e (car prim)))) Define the global environment (define global env (cons () prim)) Define indentation and output routines for the output for the evaluator (define set error msg (lambda (msg) (set! error msg msg) #f)) (define indent 0) (define output (lambda (str indent? newline?) (if tracing (if indent? (do indent)) (display str) (if newline? ))))) (define do indent (lambda () (letrec ((myindent (lambda (n) (if (> n 0) (display " ") (myindent ( n 2))))))) (myindent indent)))) =============================== ===== RULE IMPLEMENTATION ===== =============================== Page 2/11 Initialization Rule (init rule) Clears the global environment. If you want the global environment to hold an y values at start up you can places them here ; ) old init rule (define init rule (lambda () (set! env (list (cons fact (lambda (n) (if (= n 0) 1 (* n (fact ( n 1))))))))))) new init rule An environment is a pair (e,n), e is the environment bindings, and n is the parent environment. 1/6

Page 3/11 the global environment does not have a parent environment. (define init rule (lambda () (set! global env (cons () prim)))) Lambda Rule (lambda rule) As discussed a lambda form has an IMPLICIT begin in its body, so why not just put an EXPLICIT one in there and let the Begin Rule take care of business. Ex. (lambda (x) x) => (lambda (x) x)) ==========> old Lambda Rule (define lambda rule (lambda (lambda form) (let ((l (list lambda (cadr lambda form) (cons begin (cddr lambda form) )))) (output (format "=> ~a [Lambda Rule]" l) #t #t) l))) ==========> new Lambda Rule A lambda (function abstraction) must now carry with it an environment; the e nvironment belonging to a lambda form is the environment which were the present one w hen the lambda rule was called. The lambda rule must thus take in an environment as well. We will represent a lambda as a pair (l,e), where l is the actual lambda for m, and e is the associated environment, i.e., the environment to which the static l ink of any frame evaluating this lambda form must point. (define lambda rule (lambda (lambda form env) (let ((l (list lambda (cadr lambda form) (cons begin (cddr lambda form)) e nv))) (output (format "=> ~a [Lambda Rule]" (list λ (cadr l) (caddr l))) #t #t) l))) Number Rule (number rule) This rule is obsolete; it is being replaced by the Literal Rule; this allows us to use strings and boolean literals too. Though we do not have a way to comp are anything by numbers unless we implement string equal?, and and or. (define number rule (lambda (number) (output (format "=> ~a [Number Rule]" number) #f #t) number))) Literal Rule (literal rule) See the description for the Number Rule (define literal rule (lambda (literal) (output (format "=> ~a [Literal Rule]" literal) #f #t) literal))) Name Rule (name rule) Accepts a name and returns the value from the environment. Page 4/11 ==========> old Name Rule (define name rule (lambda (name) (let ((pair (assv name env))) (output (format "=> ~a [Name Rule]" (cdr pair)) #f #t) (cdr pair)) (let ((pair (assv name prim))) (output (format "=> ~a [Name Rule]" (cdr pair)) #f #t) (cdr pair)) (display (format "reference to undefined identifier: ~a" na me)) (loop)))))))) ==========> new Name Rule A call to the name rule must now include an environment, and instead of doin g an assv call on the global environment, we use lookup in environment to look through the cha in of environments. (define name rule (lambda (name env) (if tracing ) (let ((pair (lookup in environment name env #t))) (output (format "=> ~a [Name Rule]" (if (and (list? (cdr pair)) (eq? l ambda (cadr pair))) (list λ (caddr pair) (cadd dr pair)) (cdr pair))) #t #t) (cdr pair)) (display (format "reference to undefined identifier: ~a" name)) (loop)))))) Primitive Rule (primitive rule) Accepts a primitive and a list of arguments, and applies the primitive to the list of arguments using apply. Note, and and or (which we have not implemented cannot be primitives as Scheme does not allow the use of and and or with apply ; ( (define primitive rule (lambda (primitive arguments) (let ((result (apply primitive arguments))) (output (format "=> ~a [Primitive Rule]" result) #t #t) result))) 2/6

Page 5/11 Application Rule (application rule) Evaluates the arguments and calls either the primitive rule or the procedure rule. We do not need an environment here as the lambda form carries with it its own environment. ========> old Application Rule (define application rule (lambda (lst) (let ((primitive? (is primitive? (car lst))) (evaluated args (map evaluate lst))) (if primitive? (primitive rule (car evaluated args) (cdr evaluated args)) (procedure rule (car evaluated args) (cdr evaluated args)))))) ==========> new Application Rule We have recursive calls to evaluate here, so we need to bring along the envi ronment (define application rule (lambda (lst env) (let ((primitive? (is primitive? (car lst))) (evaluated args (map (evaluate form env)) lst))) (if primitive? (primitive rule (car evaluated args) (cdr evaluated args)) (procedure rule (car evaluated args) (cdr evaluated args)))))) Procedure Rule (procedure rule) The procedure rule calls subst to perform the needed substitutions according to the new procedure rule given in the handout, and the calls evaluate on the resulting form. ==========> old Procedure Rule (define procedure rule (lambda (lambda form args) (set! indent (+ indent 1)) (output (format "[Procedure Rule]") #t #t) (let ((result (evaluate (subst lambda form args)))) (set! indent ( indent 1)) result))) in the global environment. Note, if the name is already there it is simply updated using set cdr! Note, nothing stops this evaluator from having define forms that are not at the top level... just don t do that! ==========> old Define Rule (define define rule (lambda (name form) (output (format "[Define Rule]") #f #t) (let ((value (evaluate form)) (pair (assv name global env))) (set cdr! pair value) (set! global env (cons (cons name value) global env)))))) =========> new Define Rule (define define rule (lambda (name form env) (output (format "[Define Rule]") #f #t) (let ((value (evaluate form env)) (pair (lookup in environment name global env #f))) (set cdr! pair value) (set car! global env (append (car global env) (list (cons name value)) )))))) If Rule (if rule) Evaluates the boolean expression and based on the value evaluates either the true form or the false form. An if form is really a special kind of form called a special form because the word if is not evaluated. The same is true for a define form, the keyword define is not evaluated. =========> old If Rule (define if rule (lambda (test form true form false form) (output (format "[If Rule]") #f #t) (if (evaluate test form) (evaluate true form) (evaluate false form)))) Page 6/11 ==========> new Procedure Rule Instead of substituting we now simply call evaluate with the environment in which we wish to evaluate the application of the procedure. This environment if a new environment where the actual parameters are bound to the formal one s, and the parent environment is the one passed in (define procedure rule (lambda (lambda form args) (set! indent (+ indent 1)) (output (format "[Procedure Rule]") #t #t) (let* ((env (cadddr lambda form)) (new env (make new environment (map cons (cadr lambda form) args) env )) (result (evaluate (caddr lambda form) new env))) (set! indent ( indent 1)) result))) Define Rule (define rule) Evaluates the argument and binds the value of the argument to the name =========> new If Rule We need an environment here too! (define if rule (lambda (test form true form false form env) (output (format "[If Rule]") #f #t) (if (evaluate test form env) (evaluate true form env) (evaluate false form env)))) Begin Rule rule) All arguments are evaluated in order, and the value of the last evaluated form is returned. A begin form is special too, the keyword begin is not evaluated. =========> old Begin Rule (define begin rule (lambda (cmd list) (output (format "[Begin Rule]") #f #t) (car (reverse (map evaluate cmd list))))) 3/6

Page 7/11 ==========> new Begin Rule We need an environment here too. (define begin rule (lambda (cmd list env) (output (format "[Begin Rule]") #f #t) (let ((result (car (reverse (map (evaluate form env)) cmd lis t))))) result))) (letrec () b) => b) (letrec ((n1 b1)) b) ==> (let ((n1 #f)) (set! n1 b1) b)) (letrec ((n1 b1)... (nk bk)) b) => (let ((n1 #f)) (set! n1 b1) (letrec ((n2 b2)... (nk bk)) b)) Page 8/11 Let Rule (let rule) Rewrite (let ((n1 v1)... (nk vk) body) to ((lambda (n1... nk) body) v1... vk) (define let rule (lambda (let form env) (let ((n1 f1)... (nk fk) b) (output (format "[Let Rule]") #f #t) (let ((binding list (cadr let form))) (if (null? binding list) (evaluate (cons begin (cddr let form)) env) (let () b) => (be gin b) (evaluate (cons (append (list lambda ((λ (map car binding list)) (n1 n2... nk) (cddr let form)) b (map cadr binding list)) env))))) ) f1 f2... fk) (define ll (let ((f #f)) (set! f (lambda (x) (if (= x 0) 1 (* x (f ( x 1)))))) (f 4))) Let* Rule (let* rule) Rewrite (let* ((n1 v1)... (nk vk)) body) according to this: (let* () body) := body ;; (let* ((n v)) body) := (let ((n v )) body) (let* ((n1 v1)... (nk vk)) body) := (let ((n1 v1)) (let* ((n2 v2)... (nk vk)) body)) and then evaluate the new nested lambda forms/applications (define let* helper (lambda (let* form) (let ((binding list (cadr let* form))) (if (= 1 (length binding list)) (append (list let binding list) (cddr let* form)) (list let (list (car binding list)) (let* helper (append (list let* (cdr binding list)) (cddr let* form)))))))) (define let* rule (lambda (let* form env) (output (format "[Let* Rule]") #f #t) (if (null? (cadr let* form)) (evaluate (cons begin (cddr let* form)) env) (evaluate (let* helper let* form) env)))) Letrec Rule (letrec rule) (define letrec rule (lambda (letrec form env) (output (format "[Letrec Rule]") #f #t) ;; your code here! ) ) Set! Rule (set! rule) calls the helper set in environment, which is a simple modification of the deep search function that instead of returning a pair sets the cdr of it to the new value. (define set! rule (lambda (set! form env trace?) (output (format "[Set! Rule]") #f #t) (let ((name (cadr set! form)) (value (evaluate (caddr set! form) env))) (if (set in environment name env value trace?) (void) (display (format "set!: cannot set undefined identifier: ~a" name)) (loop)))))) ======================================= ====== END OF RULE IMPLEMENTATION ===== ======================================= ======================================== ===== THE MAIN EVALUATOR FUNCTIONS ===== ======================================== We need to carry an environment around when we evaluate. (define evaluate (lambda (cmd env) ; function application, primitive application or function definition? (output (format "evaluating ~a in ~a " cmd (pretty environment env)) #t #f) (if (list? cmd) can be one of: define, lambda, if, begin, or an application (case (car cmd) ((define) (define rule (cadr cmd) (caddr cmd) global env)) ((lambda) (output (format "=> #<procedure>") #f #t) (lambda rule cmd env))) ((if) (if rule (cadr cmd) (caddr cmd) (cadddr cmd) env)) () rule (cdr cmd) env)) ((let) (let rule cmd env)) ((let*) (let* rule cmd env)) ((letrec) (letrec rule cmd env)) ((set!) (set! rule cmd env #t)) (else If not one of define, lambda, if, begin, le /let*, or set! then application 4/6

Page 9/11 string (output (format "[Application Rule]") #f #t) (application rule cmd env)))) (if (or (boolean? cmd) (string? cmd) (number? cmd)) (literal rule cmd) If the command is a boolean, a number or a (name rule cmd env))))) else it must be a name ===== SYNTAX CHECKING PROCEDURES ===== ====================================== (define is form? (lambda (exp) (syntax check exp))) Page 10/11 The main read evaluate print loop (loop) 1. Read a form 2. Syntax check and evaluate 3. Print the result and recurse ==========> new loop added the global environment to the call to evaluate. (define loop (lambda () (set! indent 0) (display "> ") (let ((command (read))) (if (eq? command stop) #t (if (and (list? command) (> (length command) 0) (eq? (car command) t race)) switches tracing on and off (set! tracing (eq? (cadr command) on)) (loop)) (if (not (syntax check command)) check the syntax (or at le ast try!) (display (format "~a: ~a" type error msg)) (loop)) (let ((result (evaluate command global env))) everythin g was good, now evaluate (if (not (void? result)) (if (string? result) (display (format "Result: \"~a\"" result)) string look better with " " around (display (format "Result: ~a" result)))) (set! indent 0) (loop))))))))) (define is param list? (lambda (lst) (fold (lambda (x y) (and x y)) (map is name? lst) #t))) This is how you apply with and and or ; ) (define is name? (if (and (symbol? form) (not (number? form))) #t (set error msg (format "Not an identifier ~a." form))))) (define is lambda? (set! type "lambda") (if (not (= (length form) 3)) (set error msg (format "bad syntax in: ~a" form)) (if (not (is param list? (cadr form))) #f (if (not (is form? (caddr form))) (set error message (format "bad syntax (not a form) in: ~a" (caddr form))) #t))))) (define is begin? (set! type "begin") (fold (lambda (x y) (and x y)) (map is form? (cdr form)) #t))) (define is define? (set! type "define") (if (not (= (length form) 3)) (set error msg (format "bad syntax (multiple expression after identifier in: ~a" form)) (if (not (is name? (cadr form))) (set error msg (format "bad syntax in: ~a" (cadr form))) (if (not (is form? (caddr form))) (set error msg (format "bad syntax (not a form) in: ~a" (caddr form))) #t))))) =============================================== ===== END OF THE MAIN EVALUATOR FUNCTIONS ===== =============================================== ============================ ===== HELPER FUNCTIONS ===== ============================ fold fold is a version of apply that allows you to specify the neutral element. Example:(foldr f (a b c d) e) = f(f(f(f(e d) c) b) a) This is _really_ foldl for fold left because the neutral element and the recursion is left associative (define fold (lambda (f lst e) (if (null? lst) e (f (fold f (cdr lst) e) (car lst))))) ====================================== (define is if? (set! type "if") (if (not (= (length form) 4)) (set error msg (format "bad syntax in: ~a" form)) (if (not (is form? (cadr form))) (set error msg (format "bad syntax (not a form) in: ~a" (cadr form))) (if (not (is form? (caddr form))) (set error msg (format "bad syntax (not a form) in: ~a" (caddr form))) (if (not (is form? (cadddr form))) (set error msg (format "bad syntax (not a form) in: ~a" (caddr form)) ) #t)))))) (define is application? (fold (lambda (x y) (and x y)) (map is form? form) #t))) (define is binding list? (lambda (form lst) (if (not (list? lst)) (set error msg (format "bad syntax in: ~a" form)) (if (null? lst) #t 5/6

Page 11/11 )))) (let ((be (car lst))) (if (not (symbol? (car be))) (set error msg (format "bad syntax (not an identifier) in ~a" (car be))) (and (is form? (cadr be)) (is binding list? form (cdr lst))))) (define is let? (if (not (list? form)) (set error message (format "bad syntax in: ~a" form)) (set! type (car form)) (if (< (length form) 3) (set error message (format "bad syntax in: ~a" form)) (and (is binding list? form (cadr form)) (is form? (cons begin (cddr form))))))))) (define is let*? (is let? form))) (define is letrec? (is let? form))) (define syntax check (if (list? form) (if (= (length form) 0) (set! type "application") (set error msg (format "bad syntax in: ~a" form))) (case (car form) ((define) (is define? form)) ((lambda) (is lambda? form)) ((if) (is if? form)) () (is begin? form)) ((let) (is let? form)) ((letrec) (is letrec? form)) ((let*) (is let*? form)) (else (is application? form)))) (or (number? form) ;; numbers (symbol? form) ;; names (string? form) ;; (boolean? form))))) ======================================== ===== END OF SYNTAX CHECKING RULES ===== ======================================== (init rule) initialize (loop) GO! 6/6