implementing recursion
DESCRIPTION
Implementing Recursion. let insufficient for recursion. (let ( ( fact ( lambda (n) (if (zero? n) 1 ( * n ( fact (- n 1)) ) ) ) ) ) (fact 6) ) - PowerPoint PPT PresentationTRANSCRIPT
cs784(Prasad) L10Rec 1
Implementing Recursion
cs784(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!
cs784(Prasad) L10Rec 3
“Correct” Environment : Circularity
Old approach
cs784(Prasad) L10Rec 4
• Concrete syntax <expression> ::= letrec <procdecl>* in <expression> <idlist> ::= () | (<identifier> {, <identifier>}*)
<procdecl> ::= <identifier> <idlist> =
<expression>
• Abstract Syntax
letrec-exp
(proc-names idss bodies letrec-body)
cs784(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);
cs784(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)
cs784(Prasad) L10Rec 7
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.
cs784(Prasad) L10Rec 8
(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))) )))
cs784(Prasad) L10Rec 9
(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?)) (env environment?)))
Extended Recursive Environments
cs784(Prasad) L10Rec 10
(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))
(cont’d)
cs784(Prasad) L10Rec 11
(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))) (if (number? pos) (closure (list-ref idss pos) (list-ref bodies pos) env) (apply-env old-env sym))))))
(cont’d)
cs784(Prasad) L10Rec 12
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,[]]]
cs784(Prasad) L10Rec 13
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) (lambda (sym) (let ((pos (rib-find-position sym ids))) (if (number? pos) (list-ref vals pos) (apply-env env sym)))))
cs784(Prasad) L10Rec 14
(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)))) )) rec-env))
cs784(Prasad) L10Rec 15
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) exp)
cs784(Prasad) L10Rec 16
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))))
cs784(Prasad) L10Rec 17
(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)))))))