Implementing Recursion

Slides:



Advertisements
Similar presentations
Plt /7/ Data Abstraction Programming Language Essentials 2nd edition Chapter 2.2 An Abstraction for Inductive Data Types.
Advertisements

Cs784(Prasad)L10Rec1 Implementing Recursion. cs784(Prasad)L10Rec2 let insufficient for recursion ( (let((fact(lambda (n) (if (zero? n) 1 (* n (fact (-
1 Programming Languages (CS 550) Mini Language Interpreter Jeremy R. Johnson.
Scheme in Scheme. Why implement Scheme in Scheme  Implementing a language is a good way to learn more about programming languages  Interpreters are.
Assignments and Procs w/Params EOPL3 Chapter 4. Expressible vs. Denotable values Expressible Values –the language can express and compute these –represented.
1 Programming Languages (CS 550) Lecture Summary Functional Programming and Operational Semantics for Scheme Jeremy R. Johnson.
Functional Programming. Pure Functional Programming Computation is largely performed by applying functions to values. The value of an expression depends.
3.6 Interpreter: Recursion Recall Scheme's letrec (recursive let ): > (letrec ((fact (lambda (x) (if (zero? x) 1 (* x (fact (- x 1))))) (fact 6)) 720 Question:
Cs784(TK)1 Semantics of Procedures and Scopes. Kinds of Scope Static or Lexical scope –determined by structure of program –Scheme, C++, Java, and many.
1 Scheme Scheme is a functional language. Scheme is based on lambda calculus. lambda abstraction = function definition In Scheme, a function is defined.
Functional programming: LISP Originally developed for symbolic computing Main motivation: include recursion (see McCarthy biographical excerpt on web site).
SICP Variations on a Scheme Scheme Evaluator – A Grand Tour Techniques for language design: Interpretation: eval/apply Semantics vs. syntax Syntactic.
Functional programming: LISP Originally developed for symbolic computing First interactive, interpreted language Dynamic typing: values have types, variables.
SchemeCOP Introduction to Scheme. SchemeCOP Scheme Meta-language for coding interpreters –“ clean ” semantics Scheme = LISP + ALGOL –simple.
The environment model evaluator and compiler 1 The env model evaluator Motivation In one word: Efficiency Saves repeated renaming and substitution: Using.
1 Saves repeated renaming and substitution: explicit substitution is replaced by variable bindings using new data structures (frame, environment). Can.
EOPL3: Section 3.3 PROC and App B: SLLGEN
Cs784(tk)1 Implementing Recursion. Recap: Goals Experimenting with PL design alternatives Scoping, parameter passing, arrays,... Runnable prototype of.
PrasadL145OOL1 Managing Environments An Exercise in the Design, Analysis, Specification, and Implementation of the Core of an OOP Language. Object-Oriented.
Cs7100(Prasad)L8Proc1 Procedures. cs7100(Prasad)L8Proc2 Primitive procedures  etc User-defined procedures –Naming a sequence of operations.
Plt /12/ Data Abstraction Programming Language Essentials 2nd edition Chapter 2.3 Representation Strategies for Data Types.
3.5 Procedures Recall procedures (functions) in Scheme: (let ((f (lambda(y z) (+ y (- z 5))) (f 2 28)) We would like something similar in our toy language:
1 Objects and types Typed languages = define a set of types in the language and assign a type to each expression in the program Type checking = how can.
Plt /17/ Environment-Passing Interpreters Programming Language Essentials 2nd edition Chapter 3.8 Parameter-Passing Variations.
Basic Scheme February 8, 2007 Compound expressions Rules of evaluation Creating procedures by capturing common patterns.
1/33 Basic Scheme February 8, 2007 Compound expressions Rules of evaluation Creating procedures by capturing common patterns.
Cs784 (Prasad)L6AST1 Abstract Syntax. cs784 (Prasad)L6AST2 Language of -expressions ::= | (lambda ( ) ) | ( ) E.g., concrete syntax Scheme S-expressions.
Operational Semantics of Scheme
Lecture 4: Metacircles Eval Apply David Evans
Abstract Syntax cs7100 (Prasad) L7AST.
Basic Scheme February 8, 2007 Compound expressions Rules of evaluation
6.001 SICP Variations on a Scheme
6.001 SICP Object Oriented Programming
6.001 SICP Compilation Context: special purpose vs. universal machines
The interpreter.
Introduction to Scheme
Interpreters Study Semantics of Programming Languages through interpreters (Executable Specifications) cs7100(Prasad) L8Interp.
Closures and Streams cs784(Prasad) L11Clos
Env. Model Implementation
Original material by Eric Grimson
5.4.1: Implementation Method Invocation
2.3 Representation Strategies for Data Types
Semantics of PLs via Interpreters: Getting Started
The Metacircular Evaluator
FP Foundations, Scheme In Text: Chapter 14.
Abstract Syntax Prabhaker Mateti 1.
Dynamic Scoping Lazy Evaluation
The Metacircular Evaluator
Procedures App B: SLLGEN 1.
3.7 Variable Assignment Recall instance variables in Python:
3.4 Local Binding Recall Scheme's let: > (let ((x 5)‏ (y 6))
The Metacircular Evaluator (Continued)
6.001 SICP Further Variations on a Scheme
Extending our interpreted language with Scheme’s set!
Streams, Delayed Evaluation and a Normal Order Interpreter
Abstract Syntax cs7100 (Prasad) L7AST.
2.2.2 Abstract Syntax Recall BNF definition of l-calculus expressions:
6.001 SICP Explicit-control evaluator
3.6 Interpreter: Recursion
6.001 SICP Explicit-control evaluator
6.001 SICP Variations on a Scheme
2.2.2 Abstract Syntax Recall BNF definition of l-calculus expressions:
Chapter 3: Environment-Passing Interpreters
Assignments cs7100(Prasad) L13Assg.
Closures and Streams cs7100(Prasad) L11Clos
6.001 SICP Interpretation Parts of an interpreter
Assignments and Procs w/Params
topics interpreters meta-linguistic abstraction eval and apply
Recursive Procedures and Scopes
Rehearsal: Lazy Evaluation Infinite Streams in our lazy evaluator
Presentation transcript:

Implementing Recursion Recapitulate the goals: Experimenting with PL Design alternatives (E.g., Scoping, parameter passing mechanisms,arrays,…) 2. Runnable prototype of reference implementation. (Cf. Informal description of a programming problem with an example executable for reference.) cs7100(Prasad) L10Rec

let insufficient for recursion (let((fact(lambda (n) (if (zero? n) 1 (* n (fact (- n 1))) ) )) (fact 6) Problem : The closure to be formed must freeze the environment containing the “correct” binding for fact which is the closure itself! cs7100(Prasad) L10Rec

“Correct” Environment : Circularity Old approach cs7100(Prasad) L10Rec

Concrete syntax Abstract Syntax letrec-exp <expression> ::= letrec <procdecl>* in <expression> <idlist> ::= () | (<identifier> {, <identifier>}*) <procdecl> ::= <identifier> <idlist> = <expression> Abstract Syntax letrec-exp (proc-names idss bodies letrec-body) Whenever a construct cannot be simulated using the supported primitives, it is a candidate for addition based on its utility. cs7100(Prasad) L10Rec

Example letrec even(x) = if zero?(x) then 1 else (odd sub1(x)) odd(x) = if zero?(x) then 0 else (even sub1(x)) in (odd 13); Syntax of call and definition different to satisfy LL(1) condition required by SLLGEN?? cs7100(Prasad) L10Rec

Potential Approaches Delay the creation of the closure until a suitable environment has been formed. Create the environment and then change what one of its procedure binding points to. Simulate letrec using let and assignment in the object language, or alternatively, using assignment in the meta- language. Create the closure with a “hole” and then “install” the final environment, when available, later. Refer to EOPL (1st Ed., Chapter 7) First approach: exploit the “duration” between definition and call Second approach: requires assignment Third approach: (*not developed here*) IDEA: abstract with respect to a parameter – one-time change -> functional style; Install by calling the function (f HOLE) Abstract: (define Y (lambda (X) (f X))) Install: ( Y val) cs7100(Prasad) L10Rec

Example let x = 6 in let y = 8 in letrec p = D1 q = D2 in let z = 10 in (p) INIT-ENV : [] EXT-ENV: [x = 6,[]] EXT-ENV: [y=8, [x = 6,[]]] REC-EXT-ENV: [{p=D1,q=D2}+[y=8, [x = 6,[]]] EXT-ENV: [z=10, [{p=D1,q=D2}+[y=8, [x = 6,[]]] ] Closure: D1%[{p=D1,q=D2}+[y=8, [x = 6,[]]] cs7100(Prasad) L10Rec

Delayed Closure Creation (New Env.) So far, each procedure definition is translated as a closure (< formals, body, creation-time-environment >), and the environment binds a closure to proc name. To handle (mutually) recursive procedures, the creation of the closure is delayed until the binding for the proc name is required (using apply-env), prior to carrying out apply-proc. Exploiting available freedom: contract specifies what (extend-env + apply-env) should together achieve, not individually. cs7100(Prasad) L10Rec

(define eval-expression (lambda (exp env) (cases expression exp ... (primapp-exp (prim rands) … ) (app-exp (rator rands) (let ((proc (eval-expression rator env)) (args (eval-rands rands env))) (if (procval? proc) (apply-procval proc args) (eopl:error 'eval-expression “Applying non-procedure ~s" proc)) (proc-exp (ids body) (closure ids body env)) (let-exp (ids rands body) (let ((args (eval-rands rands env))) (eval-expression body (extend-env ids args env))) ) (letrec-exp (proc-names idss bodies letrec-body) (eval-expression letrec-body (extend-env-recursively proc-names idss bodies env))) ))) Application of closure-clause does not change. cs7100(Prasad) L10Rec

Extended Recursive Environments: Implementing Type (define-datatype environment environment? (empty-env-record) (extended-env-record (syms (list-of symbol?)) (vals vector?) (env environment?)) (recursively-extended-env-record (proc-names (list-of symbol?)) (idss (list-of (list-of symbol?))) (bodies (list-of expression?)) ) The extended recursive environment record holds three things: A list of the variables in the procdecls that is created by mapping the selector function for variables from a procdecl onto the list of procedure declarations. A vector containing procedure records (not closures) created from the formals and body of each procedure in the procedure declarations. The active environment. cs7100(Prasad) L10Rec

Detailed Implementation of the Environment Operations (define (empty-env) (empty-env-record)) (define (extend-env syms vals env) (extended-env-record syms (list->vector vals) env)) (define (extend-env-recursively proc-names idss bodies old-env) (recursively-extended-env-record proc-names idss bodies old-env)) The extended recursive environment record holds three things: A list of the variables in the procdecls that is created by mapping the selector function for variables from a procdecl onto the list of procedure declarations. A vector containing procedure records (not closures) created from the formals and body of each procedure in the procedure declarations. The active environment. cs7100(Prasad) L10Rec

(cont’d) (define (apply-env env sym) (cases environment env (empty-env-record () (eopl:error 'empty-env “Unbound ~s" sym)) (extended-env-record (syms vals old-env) (let ((pos (rib-find-position sym syms))) (if (number? pos) (vector-ref vals pos) (apply-env old-env sym)))) (recursively-extended-env-record (proc-names idss bodies old-env) (let ((pos (rib-find-position sym proc-names) )) (closure (list-ref idss pos) (list-ref bodies pos) env) )) The closure contains the letrecproc-blob and the surrounding old-env. This env is different from that of the call. cs7100(Prasad) L10Rec

Example let x = 6 in let y = 8 in letrec p = D1 q = D2 in let z = 10 in (p) INIT-ENV : [] EXT-ENV: [x = 6,[]] EXT-ENV: [y=8, [x = 6,[]]] REC-EXT-ENV: [{p=D1,q=D2}+[y=8, [x = 6,[]]] EXT-ENV: [z=10, [{p=D1,q=D2}+[y=8, [x = 6,[]]] ] Closure: D1%[{p=D1,q=D2}+[y=8, [x = 6,[]]] cs7100(Prasad) L10Rec

Another Implementation (based on procedures) (define environment? procedure?) (define (apply-env env sym) (env sym)) (define (empty-env) (lambda (sym) (eopl:error 'empty-env “Unbound ~s" sym))) (define (extend-env ids vals env) (let ((pos (rib-find-position sym ids))) (if (number? pos) (list-ref vals pos) (apply-env env sym))) )) List based rep Proc based rep Empty-env () /\x.error Extend-env cons /\x. incremental-search Apply-env cumulative-search function call BOTH SATISFY THE CONTRACT ON CORRECT LOOK-UP. cs7100(Prasad) L10Rec

(cont’d) (define (extend-env-recursively proc-names idss bodies old-env) (letrec ((rec-env (lambda (sym) (let((pos(rib-find-position sym proc-names))) (if (number? pos) (closure (list-ref idss pos) (list-ref bodies pos) rec-env) (apply-env old-env sym)))) )) ) Closure freezes an environment that contains correct bindings for mutually recursive procedures. This approach exploits the static scoping implemented by the Scheme meta-language. cs7100(Prasad) L10Rec

Simulating letrec using let and assignment (letrec ((var1 exp1) (var2 exp2)) exp ) (* exp1 and exp2 are lambda-forms *) (let ((var1 ’*) (var2 ’*)) (set! var1 exp1) (set! var2 exp2) let and assignment in the object language can allow us to simulate letrec, but only in the context of procedural values. (letrec ( (x (lambda () y)) (y 1) ) (x) ) = 1 but (letrec ( (x y) (y 1) ) x ) = error cs7100(Prasad) L10Rec

Yet Another Implementation (based on assignment) (define (extend-env-recursively proc-names idss bodies old-env) (let ((len (length proc-names))) (let ((vec (make-vector len))) (let ((env (extended-env-record proc-names vec old-env))) (for-each (lambda (pos ids body) (vector-set! vec pos (closure ids body env))) (iota len) idss bodies) env)))) (define iota (lambda (end) (let loop ((next 0)) (if (>= next end) '() (cons next (loop (+ 1 next))))))) ENV = (p q r) ([] [] []) old-env | | | These are closures that point to ENV. Hence circularity. cs7100(Prasad) L10Rec

(cont’d) (define apply-env (lambda (env sym) (cases environment env (empty-env-record () (eopl:error 'empty-env “Unbound ~s" sym)) (extended-env-record (syms vals old-env) (let ((pos (rib-find-position sym syms))) (if (number? pos) (vector-ref vals pos) (apply-env old-env sym)))) ))) cs7100(Prasad) L10Rec