Implementing Recursion

Similar documents
cs173: Programming Languages Midterm Exam

Higher-Order Functions

Implementing Continuations

cs173: Programming Languages Final Exam

Understanding Recursion

Typed Recursion {with {mk-rec : (((num -> num) -> (num -> num)) -> (num -> num)) {fun {body : ((num -> num) -> (num -> num))} {{fun {fx :

Non-Functional Procedures

Higher-Order Functions (Part I)

Threads. {seqn {spawn EXPR 1 } {spawn EXPR 2 }} Runs EXPR 1 and EXPR 2 in any order, even interleaved with each other

Functions and Recursion. Dr. Philip Cannata 1

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)

An Introduction to Functions

Variables and Bindings

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

Repetition Through Recursion

Cost of Substitution

Running FAE Programs Natively

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

Functional abstraction

State. Substitution relies on an identifer having a fxed value

Recap: Functions as first-class values

Typing Data. Chapter Recursive Types Declaring Recursive Types

Begin at the beginning

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

CPSC 311, 2010W1 Midterm Exam #2

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

Quiz. Question #1: What is the value of the following expression? {+ 1 2} Wrong answer: 0 Wrong answer: 42. Answer: 3 1-4

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

CSE341, Spring 2013, Final Examination June 13, 2013

SCHEME AND CALCULATOR 5b

CMSC 330: Organization of Programming Languages. Operational Semantics

An Explicit Continuation Evaluator for Scheme

Type Declarations. [... <id> τ... ] <id> : τ. Γ <num> : number. Γ true : boolean. Γ false : boolean. Γ e 1 : number.

To figure this out we need a more precise understanding of how ML works

def F a c t o r i a l ( n ) : i f n == 1 : return 1 else : return n F a c t o r i a l ( n 1) def main ( ) : print ( F a c t o r i a l ( 4 ) )

(Refer Slide Time: 4:00)

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

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

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

Semantics and Types. Shriram Krishnamurthi

Mutation. COS 326 David Walker Princeton University

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

The Environment Model

CS61A Notes Week 13: Interpreters

The Environment Model. Nate Foster Spring 2018

Typing Control. Chapter Conditionals

Formal Semantics. Prof. Clarkson Fall Today s music: Down to Earth by Peter Gabriel from the WALL-E soundtrack

simplefun Semantics 1 The SimpleFUN Abstract Syntax 2 Semantics

Closures. Mooly Sagiv. Michael Clarkson, Cornell CS 3110 Data Structures and Functional Programming

Functional Programming. Pure Functional Programming

Recap. Recap. If-then-else expressions. If-then-else expressions. If-then-else expressions. If-then-else expressions

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

Type Soundness. Type soundness is a theorem of the form If e : τ, then running e never produces an error

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

For this chapter, switch languages in DrRacket to Advanced Student Language.

6.001 Notes: Section 7.1

Functions BCA-105. Few Facts About Functions:

The Lambda Calculus. notes by Don Blaheta. October 12, A little bondage is always a good thing. sk

8 Understanding Subtyping

Tail Recursion: Factorial. Begin at the beginning. How does it execute? Tail recursion. Tail recursive factorial. Tail recursive factorial

6.001 Notes: Section 6.1

CS422 - Programming Language Design

CSE 341, Autumn 2005, Assignment 3 ML - MiniML Interpreter

TAIL RECURSION, SCOPE, AND PROJECT 4 11

Lecture 3: Recursion; Structural Induction

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

(Provisional) Lecture 08: List recursion and recursive diagrams 10:00 AM, Sep 22, 2017

From the λ-calculus to Functional Programming Drew McDermott Posted

Lecture 2: SML Basics

Programming Languages: Application and Interpretation

Lecture 15 Binary Search Trees

Agent Design Example Problems State Spaces. Searching: Intro. CPSC 322 Search 1. Textbook Searching: Intro CPSC 322 Search 1, Slide 1

CS 342 Lecture 8 Data Abstraction By: Hridesh Rajan

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

Principles of Programming Languages

News. Programming Languages. Recap. Recap: Environments. Functions. of functions: Closures. CSE 130 : Fall Lecture 5: Functions and Datatypes

Types, Expressions, and States

CPSC 311, 2011W1 Midterm Exam #2 2011/11/09

Programming Languages Third Edition

Discussion 12 The MCE (solutions)

Functional Programming. Pure Functional Languages

15-122: Principles of Imperative Computation, Fall 2015

Cache Coherence Tutorial

CS422 - Programming Language Design

Lectures 24 and 25: Scheduling; Introduction to Effects

Type Inference: Constraint Generation

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

Comp 411 Principles of Programming Languages Lecture 7 Meta-interpreters. Corky Cartwright January 26, 2018

Encodings. Using the minimal λ-calculus language we get. functions. local binding. booleans. numbers... and recursive functions?

CMSC330. Objects, Functional Programming, and lambda calculus

Animations involving numbers

Datatype declarations

CS125 : Introduction to Computer Science. Lecture Notes #38 and #39 Quicksort. c 2005, 2003, 2002, 2000 Jason Zych

CS115 - Module 10 - General Trees

Konzepte von Programmiersprachen

Fundamentals and lambda calculus

RACKET BASICS, ORDER OF EVALUATION, RECURSION 1

"Good" vs. "Bad" Expressions. ; interp-expr FAE... -> FAE-Value

CS112 Lecture: Defining Instantiable Classes

Transcription:

Implementing Recursion Shriram Krishnamurthi 2003-09-19 We ve seen that there are (at least two, fairly distinct ways of representing environments To implement recursive environments, we need to provide an implementation for each representation In both cases, we re trying to provide an implementation for the procedure with this type ;; arecsub: symbol symbol RCFAE env env 1 Procedural Representation of Recursive Environments Assume that we re using Scheme procedures to represent environments Let s construct this stepwise Clearly, arecsub must begin as follows: We know that somewhere, the following code pattern must reside by nature of the procedural representation of environments: (lambda (want-name [(symbol? want-name bound-name ] [else (lookup want-name env] If the symbols match, what do we want to return? Looking up identifiers in environments produces values Recall that the named expression must be a function, so its value must be a closure Thus, the response if the symbols match must yield a closure: (lambda (want-name [(symbol? want-name bound-name (closurev fun-param fun-body ] [else (lookup want-name env] What s not yet clear is what environment to close over It clearly can t be env (defeats the purpose of rec, and it must be something with this additional binding So how about we give a name to this new environment that knows about the binding for bound-name? (local ([define rec-ext-env (lambda (want-name 1

[(symbol? want-name bound-name (closurev fun-param fun-body ] [else (lookup want-name env]] Having named it, it s now easy to fill in the two ellipses What environment do we want to close over in the closure? One that has a binding for the function named in bound-name This is the environment rec-ext-env What do we want to return from this procedure? The recursively extended environment This is also rec-ext-env Thus, ignoring the box momentarily, (local ([define rec-ext-env (lambda (want-name [(symbol? want-name bound-name (closurev fun-param fun-body rec-ext-env ] [else (lookup want-name env]] rec-ext-env This definition raises two natural questions: 1 Is this really a recursive environment? Yes it is, though you ll just have to take the word of the authors of DrScheme that local does indeed define rec-ext-env as a recursive procedure, so references to that name in the procedure s body will indeed refer back to the same procedure 2 Doesn t the boxed reference to rec-ext-env have the same problem we were trying to avoid with expressions such as {rec {x x} x}? Actually, it doesn t The reference here is under a lambda, that is, it is separated from the binding instance by a procedure declaration Therefore, when the named expression portion of the local is evaluated, it associates a closure with rec-ext-env that doesn t get invoked until much later by which time the recursive environment of the local is safely defined Reassuring as these responses may be, there is still something deeply unsatisfying about this solution We set out to add recursive functions to RCFAE We reduced this to the problem of defining recursive environments, which is legitimate (and arguably, recursive environments are easier to think about than recursive functions themselves But we then implemented recursive environments by falling right back on Scheme s recursive functions: an abuse of metainterpretive power, if ever there was any! What we d like is a much more coherent, self-contained account of rec that doesn t rely on advanced knowledge of Scheme (or, at least, no knowledge of features that we don t also find in more mainstream programming languages Puzzle [Note: This is a very difficult exercise!] Is it possible to implement recursive environments using the procedural representation without employing Scheme s constructs for creating recursive procedures? That is, can lambda alone do the trick? 2 Datatype Representation of Recursive Environments Let s now turn our attention to the datatype representation of environments First, we extend the datatype: (define-datatype Env Env? [mtsub] [asub (name symbol? (value RCFA-value? (env Env?] [arecsub (name symbol? (value??? 2

(env Env?] What is the type of the value field? Obviously it must include a RCFA-value, but in fact we ll need a little more than that, as we will discover shortly Assuming we have RCFA-value as the type of the value field, let s start writing the interpreter We can be a bit lazy in the core interpreter, pushing all the work onto a helper function Thus, (define (interp expr env (cases RCFAE expr [rec (bound-id named-expr bound-body (cases RCFAE named-expr [fun (fun-param fun-body (interp bound-body (cyclically-bind-and-interp bound-id named-expr env] [else (error rec "expecting a syntactic function"]] so the interesting work happens in cyclically-bind-and-interp Before we can create a cyclic environment, we must first extend it with the new variable We don t yet know what it will be bound to, so we ll stick a dummy value into the environment: ;; cyclically-bind-and-interp : symbol RCFAE Env Env (local ([define value-holder (numv 1729] [define new-env (arecsub bound-id value-holder env] If the program uses the identifier being bound before it has its real value, it ll get the dummy value as the result But because we have syntactically verified that the named expression is a function, this can t happen 1 (Why not? Now that we have this extended environment, we can interpret the named expression in it: (local ([define value-holder (numv 1729] [define new-env (arecsub bound-id value-holder env] Because the named expression is a closure, it will close over the extended environment (new-env Notice that this environment is half-right and half-wrong: it has the right names bound, but the newest addition is bound to the wrong (indeed, dummy value Now comes the critical step The value we get from evaluating the named expression is the same value we want to get on all subsequent references to the name being bound Therefore, the dummy value the one bound to the identifier named in the rec needs to be replaced with the new value To perform this replacement, we need to ensure that the environment is mutable We will use Scheme values known as boxes to implement this 2 The type of the value field of a arecsub therefore really needs to be (lambda (x (and (box? x (RCFA-value? (unbox x 1 Suppose we lifted this restriction on the named expression In a more sophisticated implementation, we would then introduce a special kind of value that designates there s no value here ; when a computation produces that value, the evaluator should halt with an error 2 A Scheme box is a mutable cell Boxes have three operations: box : Value box, which creates a fresh cell containing the argument value; unbox : box Value, which returns the value stored in a box; and set-box! : box Value void, which changes the value held in a box 3

This forces us to box the dummy value also: (local ([define value-holder (box (numv 1729 ] [define new-env (arecsub bound-id value-holder env] Now that we have a box in the environment, it s ripe for mutation: (local ([define value-holder (box (numv 1729] [define new-env (arecsub bound-id value-holder env] (set-box! value-holder named-expr-val Since any closures in the value expression share the same binding, they automatically avail of this update Finally, we must remember that interp-and-cyclic-bind has to actually return the updated environment for the interpreter to use when evaluating the body: (local ([define value-holder (box (numv 1729] [define new-env (arecsub bound-id value-holder env] (begin (set-box! value-holder named-expr-val new-env There s one last thing we need to do Because we have introduced a new kind of environment, we must update the environment lookup procedure to recognize it (define (lookup name an-env (cases Env an-env [arecsub (bound-name bound-value-box rest-env (if (symbol? bound-name name (unbox bound-value-box (lookup name rest-env] This only differs from the rule for asub in that we must remember that the actual value is encapsulated within a box Working through our factorial example from earlier, the ambient environment is (mtsub, so the value bound to new-env in cyclically-bind-and-interp is (box (numv 1729 (mtsub Next, named-expr-val is bound to (closurev n (if0 (box (numv 1729 (mtsub Now the mutation happens This ostensibly has the effect of changing the value bound to fac in the environment: (box (closurev (mtsub 4

But we really should be writing the closure out in full Now recall that this is the same environment contained in closure bound to fac So the environment is really (if0 (mtsub where is a reference back to this very same environment! Writing this out one more level, (if0 (if0 (box (mtsub (mtsub (mtsub and so on In other words, we have a cyclic environment that addresses the needs of recursion The cyclicity ensures that there is always one more binding for fac when we need it Puzzles In the datatype implementation of environments: 1 Does anything in the rest of the code depend on the named expression being a syntactic function? Put differently, can we remove the check for a syntactic function in the rec clause of the interpreter? Are there non-syntactic expressions that can evaluate safely? 2 If we remove this check, what happens to programs that try to access the identifier being bound prematurely? Is this behavior desirable and, if not, what changes would you make to improve it? 5