190 likes | 493 Views
Semantics of Procedures and Scopes. Kinds of Scope. Static or Lexical 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
E N D
Kinds of Scope • Static or Lexical 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
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 x-> x output: 5 Scoping : Free (non-local) Variables
letx = 15 in let f = proc () x in ( letx = 8 in (f) ) + (f) Static Scoping x -> x30 Dynamic Scoping x -> x23 x -> x
Informal Semantics of Procedures • Procedure Definition • Store formal parameters and body • Procedure Invocation • Evaluate body in an environment that binds formals to actual argument values • Interpretation of free-variables • Use env. at proc. creation (static scoping) • Use env. at proc. call (dynamic scoping)
Procedures: Syntaxes • Concrete Syntax <expression> ::= … | ( <expression> +) | proc <idlist> <expression> <idlist> ::= () | ( <identifier> {, <identifier>}*) • Abstract Syntax proc-exp (ids body) app-exp (ratorrands)
Encoding Procedures • Static scoping (define-datatypeprocvalprocval? (closure (ids (list-of symbol?) (body expression?) (env environment?))) Closure retains the bindings of the free variables at procedure creation time. • Dynamic scoping (define-datatypeprocvalprocval? (procv (ids (list-of symbol?) (body expression?)))
Processing Procedure Definitions • Static scoping (define (eval-expression exp env) (cases expression exp (proc-exp (ids body) (closure idsbodyenv)) )) • Dynamic scoping (define (eval-expression exp env) (cases expression exp (proc-exp (ids body) (procvidsbody)) ))
Processing Procedure Invocations: • Static scoping (define (eval-expression exp env) (cases expression exp . . . (app-exp (ratorrands) (let ((proc (eval-expression ratorenv)) (args (eval-randsrandsenv))) (if (procval? proc) (apply-procval proc args) (eopl:error 'eval-expression “Applying non-procedure ~s" proc) ) ))
Processing Procedure Invocations • Dynamic scoping (define (eval-expression exp env) (cases expression exp (app-exp (rator rands) . . . (let ((proc (eval-expression ratorenv)) (args (eval-rands randsenv))) (if (procval? proc) (apply-procval proc args env) (eopl:error 'eval-expression "Applying non-procedure ~s" proc) ) ))
Processing Procedure Invocations • Static scoping (define (apply-procval proc args) (cases procval proc (closure (ids body s-env) (eval-expression body (extend-envids argss-env)) ))) • Dynamic scoping (define (apply-procval proc argsc-env) (cases procval proc (procv(ids body) (eval-expression body (extend-envidsargsc-env)) )))
Processing Procedure Invocations >(run "let x = 1 in let f = proc () x in (f)") 1 >(run "let x = 1 in let f = proc (x) x in (f 2)") 2 • Static scoping >(run "let x = 1 in let f = proc () x x = 5 in (f)") 1 • Dynamic scoping >(run "let x = 1 in let f = proc () x x = 5 in (f)") 5
Alternative Description: Static Scoping (define (closure ids body env) (lambda (args) (eval-expression body (extend-env ids argsenv)) ) ) (define (apply-procval procargs) (procargs) )
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.
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
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.
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
> (define x 1) > (define (f) x) > (f) 1 > (define x 2) > (f) 2 > (define (g) x) > x 2 > (g) 2 - val x = 1; - fun f () = x; val f = fn : unit -> int - f (); val it = 1 : int - val x = 2; - f () ; val it = 1 : int - fun g () = x; val g = fn : unit -> int - g (); val it = 2: int Difference between Scheme and ML