280 likes | 422 Views
Introduction to Computer Science I Topic 4: Evaluation Order and Lexical Scoping. Prof. Dr. Max Mühlhäuser Dr. Guido Rößling. Applicative vs. Normal Evaluation Order revisited. Review: Applicative order : First evaluate the operator and all operands, then substitute
E N D
Introduction to Computer Science ITopic 4: Evaluation Order and Lexical Scoping Prof. Dr. Max Mühlhäuser Dr. Guido Rößling
Applicative vs. Normal Evaluation Order revisited • Review: • Applicative order: First evaluate the operator and all operands, then substitute • Normal order: Evaluate operator, then substitute the (not evaluated) operands for the formal arguments of the operator • Stated earlier: • The result does not depend on the order of evaluation, if a result exists • Now we want to look at this last point in more detail
Applicative vs. Normal Evaluation Order revisited • Example: a “self-made” if-statement modeled as a procedure using “cond” • Seems to work fine:(my-if true 3 5) 3(my-if false 3 5) 5 • Now consider the following program: • Let us try to replace ifby my-if (define (my-if test then-exp else-exp) (cond (test then-exp) (else else-exp))) ;; ! : N -> N ;; computes the factorial function (define (! n) (if (zero? n) 1 (* n (! (pred n)))))
Applicative vs. Normal Evaluation Order revisited • Using my-if instead of if • A call such as (! 2) • does not terminate when using applicative evaluation order, • but with normal order it does • Why? ;; ! : N -> N ;; computes the factorial function (define (! n) (my-if (zero? n) 1 (* n (! (pred n)))))
Applicative vs. Normal Evaluation Order revisited • Many of the special forms in Scheme would not have to be special forms if Scheme used the normal evaluation order • e.g. if, cond, and, or • This would simplify the semantics of the language • Normal evaluation order allows for very elegant programming techniques (e.g. “streams”) • So why does Scheme (as most other languages) use applicative evaluation? • Some features such as assignments or I/O (later…) destroy confluence (the evaluation order affects the result) • In this case, we prefer the applicative evaluation order, because it is more transparent when an expression is evaluated • However, there are some modern techniques (i.e. so-called “monads”) that allow assignments, I/O, etc., while maintaining independence of the order of evaluation • This is part of the graduate course “Concepts of Programming Languages”
Block Structure • We have discussed the value of auxiliary procedures • However, there are some problems with their use: • You can quickly get lost in your code if the number of procedures gets too large • Every procedure „costs“ a name, i.e., the namespace shrinks • risk of confusion orname conflicts rises • A lot of data must be explicitly passed as parameters to the auxiliary functions • That is why it is possible to define local namesand bind them to values or procedures • Before we discuss the means in Scheme for doing so, let us review the subset of the Scheme language we have been using so far in a more formal way…
Intermezzo: Syntax & Semantics of Scheme
The syntax of a language • Like any spoken language, a programming language also has a vocabulary and a grammar: • The vocabulary is the collection of those “basic words” from which we can compose “sentences” in our language. • A sentence in a programming language is an expression or a function • The language grammar dictates how to form complete sentences from words. • The term syntaxrefers to the vocabulariesandgrammars of programming languages
The Semantics of a language • Not all grammatically correct sentences are meaningful • Neither in English nor in a programming language. • The sentence “The cat is black” is a meaningful sentence • But “the brick is a car” makes no sense, even though it is grammatically correct • To determine whether or not a sentence is meaningful, we must study the meaning, or semantics, of words and sentences • For programming languages, there are several ways to explain the meaning of individual sentences/expressions • We discuss the meaning of Scheme programs through an extension of the familiar laws of arithmetic and algebra (substitution model)
Scheme Vocabulary (Syntax) • Four categories of words, each defined by a line: • Variables (<var>): the names of functions and values • Functions (<fct>): the names of functions • Constants (<con>): boolean, symbols, and numeric constants • Primitive operations (<prm>): The basic functions that Scheme provides from the very beginning • Notation: • Lines enumerate simple examples separated by “|” • Dots indicate that there are more things of the same kind in some category
important update: <fct> added in grammar Beginning Student Scheme: The Full Grammar (Syntax) Can beempty This grammar was simplified; not all possible expressions are actually valid! Correct number of arguments • Two categories of phrases: • definitions (<def>) and expressions (<exp>)
Scheme Grammar: Examples • Examples of expressions: • 'all: symbol, hence, an expression • x: every variable is an expression • (f x): a function application, because x is a variable • The following sentences are notcorrectexpressions: • (fdefine): partially matches shape of a function application but uses define as if it were a variable • (cond x): fails to be a correct cond-expression because it contains a variable as the second item, not a pair of expressions surrounded by parentheses • (): grammar requires that every left parenthesis is followed by something other than a right parenthesis
Grammatical Terminology • A definition (<def>) consists of: • Header: The 2nd component of a definition, i.e., the non-empty sequence of variables • Parametersof a function: The variables that follow the first variable in a header • Body: The expression component of a definition • An applicationconsists of • Function: The first component • Arguments(actual arguments): the remaining components • A cond-expression consists of cond-lines (cond-clauses) each consisting of two expressions: • Question(condition) and answer (define(<function-name> <parameter> ...<parameter>) <body>) (<function-name> <argument> ...<argument>) (cond(<question> <answer>) <cond-clause> ...)
Syntax of the local-expression (local ((define PI 3)) (* PI 5 5)) • Local definition:parenthesized sequence following the keyword local • Definitions in the local definition block are called “LOCALLY DEFINED” variables, functions, or structures. • Definitions in the Definitions window are called “TOP-LEVEL DEFINITIONS” • Each name may occur at most once on the left-hand side, be it in a variable definition or a function definition. • The expression in each definition is called the RIGHT-HAND SIDE expression • Body:expression (<exp>) following the definitions <exp> = ... | ( local (<def-1> ...<def-n>) <exp> )
Block Structure: Example (local ( (define (f x) (+ x 5)) (define (g alon) (cond [(empty? alon) empty] [else (cons (f (first alon)) (g (rest alon)))]))) (g (list 1 2 3)) ) LOCAL DEFINITION • two locally defined procedures: f and g • g calls f • body calls g BODY
Properties of Local Definitions • The body of the local definition can access names defined outside its scope • Auxiliary procedure plus-y-sqr can access y • When using a non-local definition, y would have to be passed explicitly • Thus, local definitions can lead to less parameters • Locally defined names are not visible from the outside • The same name can be re-used in a different local definition (define (f x y z) (local ( (define (square n) (* n n)) (define (plus-y-sqr q) (square (+ q y)))) (+ (plus-y-sqr x) (plus-y-sqr z)))) (x+y)² + (z+y)²
Properties of Local Definitions • By being just a new type of an expression, a local expression can be used universally where an expression is expected • as an operator or operand or as a body of a procedure • closure property • In particular, local definitions can be nested arbitrarily (so-called block structure) • e.g., in the body of a local expression, or a local definition • scalability (define (f x y z) (local ( (define (plus-y-sqr q) (local ( (define (square n) (* n n))) (square (+ q y))))) (+ (plus-y-sqr x) (plus-y-sqr z)))) (x+y)² + (z+y)²
Properties of Local Definitions • An important property of local definitions islexical scoping • Scoping is the strategy for associating a name to a definition • Lexical scoping means that the next definition in the nesting structure is used • For example, we could rename the parameter of square from n to z • However, z will not be confused in the body of square with the parameter z of function f Conceals outer zinside of square (define (f x y z) (local ( (define (square z) (* z z)) (define (plus-y-sqr q) (square (+ q y)))) (+ (plus-y-sqr x) (plus-y-sqrz)))) (x+y)² + (z+y)² 19
Lexical scoping • It is important to distinguish between name binding, bound namesand free namesto understand lexical scoping • „free“ and „bound“ are always relative to an expression namebinding (local ( (define (square x) (* x x)) (define (ge q) (square (+ q y)))) (+ (ge x) (ge z)))) freename boundname
Lexical scoping • The scopeof a name bindingis the textual region in which an occurrence of the name relates to that name binding • Top-level definitions have global scope • The scope of a procedure parameter is the body of the procedure • The scope of a local definition is the expression (last operand) in the localdefinition • As we have seen, there can be “holes” in the scope of a name binding • When a name binding is concealed by a binding of the same name
Try the lexical scoping with the „Check Syntax“ Feature of DrScheme
Reminder: Evaluation Rule for Procedures • Evaluation rule for procedures • The procedure is a primitive procedure → execute the respective machine instructions. • The procedure is a compound procedure • Evaluate the procedure body; • substitute each formal parameter with the respective current value that is passed when applying the procedure. (define (f x ) (* x x)) (f 5 )
Parameter substituion and lexical scope • Do not blindly substitute parameters by the current values! • Keep the scope rules in mind • Only substitute occurrences of parameters names in the scope of the parameter definition • More precisely: Only the occurrences of the name which are free in the procedure body must be substituted • Example: • x is not substituted by 2 in square • x is not free in square (define (f x y z) (local ( (define (square x) (* x x)) (define (plus-y-sqr q) (square (+ q y)))) (+ (plus-y-sqr x) (plus-y-sqr z)))) (f 2 3 4)
Evaluation of localblocksin the substitution model • We need to extend the substitution model to evaluate local blocks • Until now, we do not have a rule for local blocks • Idea: Local definitions are “drawn” to Top-Level • During this process, we have to assign “fresh” names • This must be done in every evaluation of the local definition • Can not be done statically
Evaluation of localblocks: Example (define y 10) (+ y (local ((define y 10) (define z (+ y y))) z)) Step 1: Renaming local names with “fresh” names (define y 10) (+ y (local ((define y1 10) (define z1 (+ y1 y1))) z1)) Step 2: Extracting local definitions to the topmost level (define y 10) (define y1 10) (define z1 (+ y1 y1)) (+ y z1) For the remaining evaluation, we can proceed according to the existing substitution model
Using local • Guidelines for the use of local : • If you notice during the development of a procedure using our design recipe that you need an auxiliary procedure which is only needed by that procedure, define the auxiliary procedure inside of a local block. • Use the fact that inside of the local block, you have access to names that lie (lexically) further outside (e.g., parameters of procedures). • If you compute a value several times inside a procedure body, define a local name for this value and use it in those places where you have computed the value before.
Using local: Example (define (make-rat n d) (make-xy (/ n (gcd n d)) (/ d (gcd n d)))) (define (make-rat n d) (local ((define t (gcd n d))) (make-xy (/ n t) (/ d t))))