Download presentation
Presentation is loading. Please wait.
1
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
2
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
3
“Correct” Environment : Circularity
Old approach cs7100(Prasad) L10Rec
4
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
5
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
6
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
7
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
8
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
9
(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
10
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
11
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
12
(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
13
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
14
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
15
(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
16
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
17
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
18
(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
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.