170 likes | 309 Views
This guide delves into user-defined procedures in L8Proc, exploring naming sequences, recursion, and scoping rules such as static and dynamic scoping. Learn how to define and invoke procedures, manage free variables, and the semantic implications of scoping. The concrete and abstract syntax for defining procedures is presented, alongside examples to demonstrate their execution. The piece also discusses the pros and cons of different scoping rules, and their applications in exception handling and formatting, offering insights to both new and experienced programmers.
E N D
Procedures L8Proc
Primitive procedures • +, -, *, etc • User-defined procedures • Naming a sequence of operations • triple = proc (x) +(x,+(x,x)) • 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