Com S 342 meeting -*- Outline -*- * static properties of variables (EOPL2e 1.3) Motivation: now we move back from how to program to the study of languages in general Still using (subsets of) Scheme for examples, however. ** static vs. dynamic properties ------------------------------------------ STATIC VS. DYNAMIC PROPERTIES (1.3) def: a property of a language is: - *static* if - *dynamic* if Static properties are important for ------------------------------------------ ... it can be checked (in general) before running the program ... it cannot be checked (in general) before running the program ... code improvement (so-called optimization), for reasoning about correctness, and for consistency checking (such as type checking). Q: Are the dynamic ones important too? Yes, but not for optimization or correctness ** variable bindings, static (1.3.1) ------------------------------------------ THE LAMBDA CALCULUS (1.3.1) lambda-1-exp Why? - core of most programming languages - only naming Grammar: ::= ------------------------------------------ we'll call this lambda-1-exp to distinguish it from other versions, the 1 refers to the 1-argument nature of the procedures ... "var-exp (id)" | (lambda () ) "lambda-exp (id body)" | ( ) "app-exp (rator rand)" Q: Can you give some examples in this grammar? Q: Can you write a derivation of (lambda (x) x) using this grammar? The traditional syntax for the 2nd rule is with greek lambda and dot: (\ . ) The meaning is like in Scheme, think of (lambda (x) ...) as a declaration of x, with value to be supplied by a call (application). Note the differences between use of variables in a varref and declaration in a lambda as the formal. *** free and bound variable references ------------------------------------------ FREE AND BOUND VARREFS def: In (lambda () ) the is the declaration of a formal parameter and *binds* all occurrences of that variable in , unless there is an intervening declaration of the formal. ((lambda (b) b) (car f)) (((lambda (b) (lambda (b) (b f))) f) f1) def: a variable x *occurs free* in E iff def: a variable x *occurs bound* in E iff E contains a use of x that is bound by a declaration of x in E --------------------------------------------------------- Q: in the expression, what does b refer to? car? f? Draw arrows from uses to declarations in the two examples (note, opposite to the arrows in DrScheme) Be sure they understand what "intervening declarations" mean before going on ... E contains a use of x that is not bound by any declaration of x in E --------------------------------------------------------- EXAMPLES f, f1 occur free in: f (f f1) (lambda (b) f) b, b1 occur bound in: (lambda (b) b) (lambda (b1) (lambda (b) (b1 b))) There can be a mix: ((lambda (b) b) f) ^ ^ bound-/ \-free occurrence occurrence The same variable can occur both free and bound ((lambda (n) n) n) ^ ^ bound-/ \-free occurrence occurrence Variables that are free in a subexpression may be bound in a larger expression (lambda (f) ((lambda (b) (b f1)) f) ) --------------------------------------------------------- Q: So if n occurs free in a expression, does that mean it doesn't occur bound? ------------------------------------------ FOR YOU TO DO What are the (a) free, and (b) bound variables in ... (lambda (x) (lambda (y) x)) (g (cdr x)) (lambda (x) (g (cdr x))) (lambda (g) (lambda (x) (g (cdr x)))) ------------------------------------------ The book gives the following using the characteristic predicates, i.e., x occurs free in E iff... ------------------------------------------ CONSTRUCTIVE DEFINITIONS notation: FV(E) = set of variables that occur free in E BV(E) = set of variables that occur bound in E def: FV(E) = {x}, if E is a varref, x , if E is (E1 E2), and , if E is (lambda (y) E) def: BV(E) = {}, if E is a varref , if E is (E1 E2), and , if E is (lambda (y) E) ------------------------------------------ ... FV(E1) \union FV(E2) ... FV(E) - {y} ... BV(E1) \union BV(E2) ... BV(E) \union ({y} \intersect FV(E)) ------------------------------------------ MORE TERMINOLOGY lexically bound = globally bound = dependency: (lambda (ls) (car (car ls))) closed expression, combinator = SOME COMBINATORS (lambda (n) n) ; I (lambda (x) ; K (lambda (y) x)) (lambda (x) ; S (lambda (y) (lambda (z) ((x z) (y z))))) ------------------------------------------ a variable reference is: ... bound to a formal parameter in a surrounding lambda ... bound at the top level it's an error in Scheme if a variable isn't lexically or globally bound the lambda given is dependent on the value of car, if that is changed, it does something different. ... a term with no free variable references interesting that these 3 combinators suffice to program any computable function! ** scope and lexical address (1.3.2) Now we're going to switch grammars a bit, and allow multiple arguments to applications, and multiple formals ------------------------------------------ VARIABLE DECLARATION REGIONS !-----------------------------! ! (lambda (x) ! ! !----------------------! ! ! ! (lambda (y) ! ! ! ! ! ! ! ! (car (cons x y)) )!) ! ! !----------------------! ! !-----------------------------! (lambda (x) (lambda (x) (+ x 3) ) ) def: a variable declaration's *region* is an area of the program's text that includes the declaration, and within which def: a variable declaration's *scope* is that part of its region within which ------------------------------------------ - point out the regions, contours A region is the area occupied by a lambda-expression. - show how to draw arrows from varrefs to formal declarations ... the declaration *may* have effect (varrefs may refer to it) ... the declaration *does* have effect (varrefs will refer to it) Note: region and scope refer to declarations, not variables. however, sometimes people confuse the two, (ok when the same variable isn't used in 2 declarations, but can lead to confusion otherwise.) motto: declarations have scope, not variables names. The following shows this ------------------------------------------ FOR YOU TO DO (lambda (x) (lambda (y) ((lambda (x) (x y)) x) ) ) 1. Draw arrow from each variable reference to its declaration. 2. Draw the contours. 3. What is the scope of each declaration? TERMINOLOGY hole in the scope = ------------------------------------------ ... subarea of a var declaration's region in which the var declaration has no effect. point out the hole in the scope above. Q: Is there a hole in the declaration of y's scope? *** lexical depth This is used in compilers to tell how many static links to traverse to find the variable's declaration. ------------------------------------------ LEXICAL DEPTH def: the lexical depth of a variable use is !-----------------------------! ! (lambda (x) ! ! !----------------------! ! ! ! (lambda (y) ! ! ! ! ! ! ! ! (car (cons x y)) )!) ! ! !----------------------! ! !-----------------------------! ------------------------------------------ ... the number of contours crossed in going from the variable use to its declaration. For this language, contours are the same as lambda-expressions, so the number of contours crossed is the same as the number of lambdas exited Q: What's the lexical depth of y? x? cons? car? *** lexical address compilers don't want to deal with names for variables, work better with numbers what they use is a pair of numbers to access each variable: lexical depth (number of static links), and the lexical position (an offset within activation frame) ------------------------------------------ LEXICAL ADDRESS identify each varref by 2 numbers: d = lexical depth p = position, counted from 0 format: (v : d p) ^ \-------- var name (lexical-address (parse-expression 'cdr)) ==> (cdr : 0 0) (lexical-address (parse-expression '(lambda (ls) (cdr ls)))) ==> (lambda (ls) ((cdr : 1 0) (ls: 0 0))) (lexical-address (parse-expression '(lambda (x) (lambda (y) (car (cons x y)))))) ==> (lambda (x) (lambda (y) ((car : ) ((cons : ) (x : ) (y : ))))) ------------------------------------------ ... can erase the names, unless needed for debugging (as in -g option of CC) ------------------------------------------ FOR YOU TO DO What is?... (lexical-address (parse-expression '(lambda (x) (lambda (y) x)))) (lexical-address (parse-expression '(lambda (x) (lambda (x) x)))) (lexical-address (parse-expression '(lambda (x) (lambda (z) x)))) (lexical-address (parse-expression '(lambda (a b c) (lambda (f g) (f (g a b) c a))))) ------------------------------------------ allowing more than one var in a lambda above, and more than one expression in an application this is as in homework *** renaming variables (skip) The first program transformation rule this course, we'll see several, all useful in rewriting programs. Q: do variable names really matter to a compiler? What matters is the shape of an expression, that is, what variables refer to what var declarations, as in lexical-address computation ------------------------------------------ RENAMING FORMALS Which are equivalent? (lambda (x) (lambda (y) x)) ; a (lambda (x) (lambda (x) x)) ; b (lambda (x) (lambda (z) x)) ; c (lambda (m) (lambda (y) m)) ; d (lambda (m) (lambda (y) x)) ; e Problems in renaming variables: - capture, as in - respecting inner bindings, as in ------------------------------------------ Q: What are their lexical address forms? ... changing y in a to x, producing b, instead of c ... changing x in a to m, producing e, instead of d ------------------------------------------ FOR YOU TO DO Are these equivalent? (lambda (x) ((lambda (x) (cons x '())) (cons x '()))) and (lambda (y) ((lambda (x) (cons y '())) (cons y '()))) ------------------------------------------ ... no