170 likes | 291 Views
Procedures. Primitive procedures +, -, *, etc User-defined procedures Naming a sequence of operations triple = proc (a) + (a, + (a,a)) Recursive definitions exp = proc (x, i) if (i = 0) then 1 else * (x, exp (x,i-1)). User-defined procedures. Concrete Syntax
E N D
Procedures L8Proc
Primitive procedures • +, -, *, etc • User-defined procedures • Naming a sequence of operations • triple = proc (a) +(a,+(a,a)) • Recursive definitions • exp = proc (x, i) if (i = 0) then 1 else*(x,exp(x,i-1)) L8Proc
User-defined procedures Concrete Syntax <expression> ::= … | ( <expression> +) | proc <idlist> <expression> <idlist> ::= () | ( <identifier> {, <identifier>}*) Abstract Syntax proc-exp (ids body) app-exp (rator rands) Examples proc (y,z) *(y,5) (f x 5) L8Proc
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 L8Proc
letx = 15 in let f = proc () x in ( letx = 8 in (f) ) + (f) Static Scoping x -> x30 Dynamic Scoping x -> x23 x -> x L8Proc
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) L8Proc
Encoding Procedures • Static scoping (define-datatype procval procval? (closure (ids (list-of symbol?)) (body expression?) (env environment?))) Closure retains the bindings of the free variables at procedure creation time. • Dynamic scoping (define-datatype procval procval? (procv (ids (list-of symbol?)) (body expression?))) L8Proc
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) (procv idsbody)) )) L8Proc
Processing Procedure Invocations • Static 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) (eopl:error 'eval-expression “Applying non-procedure ~s" proc))) ) )) L8Proc
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))) ) )) L8Proc
Processing Procedure Invocations • Static scoping (define (apply-procval proc args) (cases procval proc ( closure (ids body s-env) (eval-expression body (extend-env ids argss-env)) ))) • Dynamic scoping (define (apply-procval proc args c-env) (cases procval proc ( procv (ids body) (eval-expression body (extend-env idsargsc-env)) ))) L8Proc
Processing Procedure Invocations • Static scoping >(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 >(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 L8Proc
Alternative Description: Static Scoping (define (closure ids body env) (lambda (args) (eval-expression body (extend-env ids argsenv)) ) ) (define (apply-procval procargs) (procargs) ) L8Proc
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. • First LISP evaluator used dynamic scoping by accident!! • Meaning of a call depends on the context. L8Proc
Pros and cons of scoping rules • It is easy to implement recursion in a dynamically scoped language. Historically, LISP uses dynamic scoping. • In dynamic scoping, the interpretation of a free variable in a function body can change based on the context (environment) of a call. Renaming a formal parameter in the caller can effect the semantics of a program, if renamed parameter now captures a free variable in the called function. (Locality of formals destroyed.) L8Proc
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 L8Proc
> (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 L8Proc