implementing recursion

17
cs784(Prasad) L10Rec 1 Implementing Recursion

Upload: elaine-hart

Post on 31-Dec-2015

20 views

Category:

Documents


0 download

DESCRIPTION

Implementing Recursion. let insufficient for recursion. (let ( ( fact ( lambda (n) (if (zero? n) 1 ( * n ( fact (- n 1)) ) ) ) ) ) (fact 6) ) - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Implementing Recursion

cs784(Prasad) L10Rec 1

Implementing Recursion

Page 2: 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!

Page 3: Implementing Recursion

cs784(Prasad) L10Rec 3

“Correct” Environment : Circularity

Old approach

Page 4: Implementing Recursion

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)

Page 5: Implementing Recursion

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);

Page 6: Implementing Recursion

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)

Page 7: Implementing Recursion

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.

Page 8: Implementing Recursion

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))) )))

Page 9: Implementing Recursion

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

Page 10: Implementing Recursion

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)

Page 11: Implementing Recursion

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)

Page 12: Implementing Recursion

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,[]]]

Page 13: Implementing Recursion

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)))))

Page 14: Implementing Recursion

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))

Page 15: Implementing Recursion

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)

Page 16: Implementing Recursion

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))))

Page 17: Implementing Recursion

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)))))))