Presentation is loading. Please wait.

Presentation is loading. Please wait.

Recursive Procedures and Scopes

Similar presentations


Presentation on theme: "Recursive Procedures and Scopes"— Presentation transcript:

1 Recursive Procedures and Scopes
EOPL3 Sections 1

2 The LETREC Language All of PROC, plus … Concrete: AST:
Expression in Expression AST: proc-body letrec-body) CS7100(pm) 2 2

3 value of a letrec expression
bound-var proc-body letrec-body) ρ) = (value-of letrec-body bound-var proc-body ρ)) CS7100(pm) 3 3

4 (extend-env-rec pnm bvar pbdy ρ)
Let ρ1 == (extend-env-rec proc-name bound-var proc-body ρ) (procedure bound-var proc-body ρ1)) (apply-env ρ1 var) = (apply-env ρ var) CS7100(pm) 4 4

5 environment datatype (define-datatype environment environment?
(empty-env) (extend-env (var identifier?) (val expval?) (env environment?)) (extend-env-rec (p-name identifier?) (b-var identifier?) (body expression?) (env environment?))) CS7100(pm) 5 5

6 apply-env (define apply-env (lambda (env search-var)
(cases environment env (empty-env () (report-no-binding-found search-var)) (extend-env (saved-var saved-val saved-env) (if (eqv? saved-var search-var) saved-val (apply-env saved-env search-var))) (extend-env-rec (p-name b-var p-body saved-env) (if (eqv? search-var p-name) (proc-val (procedure b-var p-body env)) (apply-env saved-env search-var)))))) CS7100(pm) 6 6

7 Exercise 3.35 “The representations we have seen so far are inefficient, because they build a new closure every time the procedure is retrieved. But the closure is the same every time. We can build the closures only once, by putting the value in a vector of length 1 and building an explicit circular structure, like …” . CS7100(pm) 7 7

8 Exercise 3.35: extend-env-rec
(define extend-env-rec (lambda (p-name b-var body saved-env) (let ((vec (make-vector 1))) (let ((new-env (extend-env p-name vec saved-env))) (vector-set! vec 0 (proc-val (procedure b-var body new-env))) new-env)))) CS7100(pm) 8 8

9 Scoping and Binding references declarations lexical scoping rules
(f x y) f, x, and y declarations (lambda (x) (+ x 3)) (let ((x (+ y 7))) (+ x 3)) y, and second x are refs first x is a declaration lexical scoping rules CS7100(pm) 9 9

10 Kinds of Scope Static or Lexical scope Dynamic scope Global Scope
determined by structure of program Scheme, C++, Java, and many compiled languages Dynamic scope determined by path of execution Lisp dialects, Perl, and many interpreted languages Global Scope File scope Local Scope Block Body of a procedure Body of a loop Scope alters the meaning CS7100(pm) 10 10

11 Scoping : Free (non-local) Variables
proc main() int x := 5; proc q() { x := x + 1;} proc r() {int x := 0; q();} {r(); print(x); } Static scoping x -> x output: 6 Dynamic scoping output: 5 CS7100(pm) 11 11

12 Static Scoping x -> x 30 Dynamic Scoping x -> x 23 x -> x
let x = 15 in let f = proc () x in ( let x = 8 in (f) ) (f) Static Scoping x -> x Dynamic Scoping x -> x x -> x CS7100(pm) 12 12

13 Fig 3.13 Contour diagram CS7100(pm) 13 13

14 Figure 3.14 Contour diagram
CS7100(pm) 14 14

15 Binding Rules A variable declared by a proc is bound when the procedure is applied. = (value-of body (extend-env var val ρ)) A let-variable is bound by the value of its right-hand side. = (value-of body (extend-env var val ρ)) A variable declared by a letrec is bound using its right-hand side as well. bound-var proc-body ρ)) CS7100(pm) 15 15

16 lexical depth # of contours crossed zero-based indexing (lambda (x) (
(lambda (a) (x a)) x)) (nameless-lambda ( (#1 #0)) #0)) CS7100(pm) 16 16

17 The Translator Source: var-exp, let-exp, …
Target: nameless-var-exp, nameless-let-exp translation-of: handles expressions translation-of-program: handles programs. translation-of-program runs translation-of in a suitable initial static environment. CS7100(pm) 17 17

18 translation-of-program
(define translation-of-program (lambda (pgm) (cases program pgm (a-program (exp1) (a-program (translation-of exp1 (init-senv))))))) (define init-senv (lambda () (extend-senv ’i (extend-senv ’v (extend-senv ’x (empty-senv)))))) CS7100(pm) 18 18

19 Fg 3.16 lexical-address translator
(define translation-of (lambda (exp senv) (diff-exp (exp1 exp2) (diff-exp (translation-of exp1 senv) (translation-of exp2 senv))) … altogether 8 cases … (else (report-invalid-source-expression exp)) ))) Senv = Listof(Sym) Lexaddr = N CS7100(pm) 19 19

20 translation-of zero?-exp
(zero?-exp (exp1) (zero?-exp (translation-of exp1 senv))) CS7100(pm) 20 20

21 translation-of if-exp
(if-exp (exp1 exp2 exp3) (if-exp (translation-of exp1 senv) (translation-of exp2 senv) (translation-of exp3 senv))) CS7100(pm) 21 21

22 translation-of var-exp
(var-exp (var) (nameless-var-exp (apply-senv senv var))) CS7100(pm) 22 22

23 translation-of let-exp
(let-exp (var exp1 body) (nameless-let-exp (translation-of exp1 senv) (translation-of body (extend-senv var senv)))) CS7100(pm) 23 23

24 translation-of proc-exp
(proc-exp (var body) (nameless-proc-exp (translation-of body (extend-senv var senv)))) CS7100(pm) 24 24

25 translation-of call-exp
(call-exp (rator rand) (call-exp (translation-of rator senv) (translation-of rand senv))) CS7100(pm) 25 25

26 Our top-level procedure
(define run (lambda (string) (value-of-program (translation-of-program (scan&parse string))))) CS7100(pm) 26 26

27 nameless environments
nameless-environment? : SchemeVal → Bool empty-nameless-env : () → Nameless-env extend-nameless-env : Expval × Nameless-env → Nameless-env apply-nameless-env : Nameless-env × Lexaddr → DenVal = (value-of body (extend-env var val ρ)) page 79 = (value-of body (extend-nameless-env val ρ)) page 98 CS7100(pm) 27 27

28 procedure datatype (define-datatype proc proc? (procedure
(body expression?) (saved-nameless-env nameless-environment?))) CS7100(pm) 28 28

29 apply-procedure (define apply-procedure (lambda (pc val)
(cases proc pc (procedure (body saved-nameless-env) (value-of body (extend-nameless-env val saved-nameless-env)))))) CS7100(pm) 29 29

30 redefine value-of (define value-of (lambda (exp nameless-env)
(cases expression exp (const-exp (num) ...as before...) (diff-exp (exp1 exp2) ...as before...) (zero?-exp (exp1) ...as before...) (if-exp (exp1 exp2 exp3) ...as before...) (call-exp (rator rand) ...as before...) … next slide … (else (report-invalid-translated-expression exp))))) CS7100(pm) 30 30

31 redefine value-of (nameless-var-exp (n)
(apply-nameless-env nameless-env n)) (nameless-let-exp (exp1 body) (let ((val (value-of exp1 nameless-env))) (value-of body (extend-nameless-env val nameless-env)))) (nameless-proc-exp (body) (proc-val (procedure body nameless-env))) CS7100(pm) 31 31

32 value-of-program (define value-of-program (lambda (pgm)
(cases program pgm (a-program (exp1) (value-of exp1 (init-nameless-env)))))) CS7100(pm) 32 32

33 extra slide if time permits
======================================================================================================================================================================================================================================================== CS7100(pm) 33 33

34 Procedure Invocations
Dynamic scoping (define (eval-expression exp env) (cases expression exp (app-exp (rator rands) . . . (let ((proc (eval-expression rator env)) (args (eval-rands rands env))) (if (procval? proc) (apply-procval proc args env) (eopl:error 'eval-expression "Applying non-procedure ~s" proc) ) )) CS7100(pm) 34 34

35 Processing Procedure Invocations
Dynamic scoping (define (apply-procval proc args c-env) (cases procval proc (procv (ids body) (eval-expression body (extend-env ids args c-env)) ))) CS7100(pm) 35 35

36 Processing Procedure Invocations
>(run "let x = 1 in let f = proc () x in (f)") 1 let f = proc (x) x in (f 2)") 2 Static scoping x = 5 in (f)") Dynamic scoping let f = proc () x x = 5 5 CS7100(pm) 36 36

37 Implementing Dynamic Scoping
The value of variable x is the last value bound to x => stack discipline Deep binding Use a global stack for all variables Shallow binding Use a separate stack for each variable Implementing recursion is trivial. Meaning of a call depends on the context. Recursion easy to implement in dynamically scoped language: (let f = proc (x) if 0 then 0 else f(x-1) in (f 5)) More interestingly, consider a mutually recursive definition. CS7100(pm) 37 37

38 Lexical Scope Pros and Cons
Scope of names is known to the compiler. Permits type checking by compiler Easily check for uninitialized variables Easier to analyze program correctness Recursion is harder to implement CS7100(pm) 38 38

39 Dynamic Scope Pros and Cons
Meaning of variables known only at run-time. Cannot perform type checking before execution Programs are flexible, but harder to understand Easy to implement recursion Renaming in the caller can effect the semantics of a program Locality of formals destroyed. if renamed parameter now captures a free variable in the called function. Recall the interpretation of a free variable in a function body can change based on the context (environment) of a call. CS7100(pm) 39 39

40 Dyn Binding Can be Difficult
Exercise 3.29: … dynamic binding may be exceptionally difficult to understand. For example, under lexical binding, consistently renaming the bound variables of a procedure can never change the behavior of a program: we can even remove all variables and replace them by their lexical addresses, as in section 3.6. But under dynamic binding, this transformation is unsafe. For example, under dynamic binding, the procedure proc (z) a returns the value of the variable a in its caller’s environment. Thus, the program let a = 3 in let p = proc (z) a in let f = proc (x) (p 0) in let a = 5 in (f 2) returns 5, since a’s value at the call site is 5. What if f’s formal parameter were a? CS7100(pm) 40 40

41 Application of Dynamic Scoping
Exception Handling provide a separate construct in statically scoped language Setting Local Formatting Parameters Input-Output Redirection avoids passing parameters explicitly through “intermediate” procedures CS7100(pm) 41 41

42 Dyn Binding Can be Powerful
Exercise 3.37 With dynamic binding, recursive procedures may be bound by let; no special mechanism is necessary for recursion. Test the following let fact = proc (n) add1(n) in let fact = proc (n) if zero?(n) then 1 else *(n,(fact -(n,1))) in (fact 5) using both lexical and dynamic binding. CS7100(pm) 42 42


Download ppt "Recursive Procedures and Scopes"

Similar presentations


Ads by Google