================================================================== END OF PART I OF COURSE Nothing after this will be tested on prelim 1 ================================================================== NEW TOPIC -- assignment, state variables, the environment model The *critical* element of the course so far is the substitution model. We're about to step beyond it (Newton to Einstein). So far, all of our programs have been FUNCTIONAL PROGRAMS (Well, almost all -- not I/O, define) They can be thought of as pure mathematical functions. (foo 10) ==> 18 (foo 10) ==> 18 If foo is a mathematical function, (foo 10) will *always* return the same thing * As long as foo hasn't been redefined. ---------------------------------------------------------------------- Now, we change all that. New special form: set! (set! symbol expression) which CHANGES the value associated with symbol to the value of the expression. (set! x (inc x)) * symbol is NOT evaluated * expression IS evaluated It is illegal to set! a symbol that doesn't exist. We CREATE variables by * define * let, let*, letrec * parameters to a procedure set! just CHANGES the values of variables. (define a 10) ;; a is now 10 (set! a 20) ;; a is now 20 (set! a #t) ;; a is now true SUBTLETY (beyond the scope of this course): side-effects introduce a notion of time into programs. That's why they are (a) necessary and (b) problematic. set! is used for its EFFECT, not its VALUE. most define/define-method Scheme set! exprs print VALUE yes no EFFECT no yes set! can be useful for programming, as we will see. [not as useful as all you := junkies think though] ---------------------------------------------------------------------- It also trashes the substitution model. (define (put-in-bowl thing) (set! thing (pair thing '(in a bowl))) thing) If we do the substitution model computations on put-in-bowl, we'll substitute whatever argument is passed for the parameter thing, and thus the model says that the function will always return whatever value was input. That is (put-in-bowl 'goldfish) will (according to the substitution model): 1. Substitute goldfish for thing everywhere in the body 2. Do something to handle set! -- doesn't really matter what 3. Return the final thing, which is {goldfish} So, the model says it will return goldfish, which is wrong, it returns (goldfish in a bowl) ---------------------------------------------------------------------- We need some way to talk about changing values. Substitution model fails: we cannot simply substitute a value for a name, because the value of a name may be changed. But there may be many different variables with the same name (define x 'barney) (let ((x 'purple) (y (set! x 'monster))) x) ==> monster x ==> barney Since there can be many different variables called x at the same time --> Must change the *right* one. --> Need a model that lets us take care of that. Another example not involving set!: (define x 10) (define foo (lambda () x)) (let ((x 15)) (foo)) => ??? The issue here is STATIC vs. DYNAMIC SCOPING. The answer is 10, because Dylan is statically scoped, which means free variables are resolved in the environment of the function DEFINITION (static scoping), not the environment of the function CALL (dynamic scoping). Dylan's granddaddy LISP is dynamically scoped. LISP would return 15 in this case. Most modern programming languages (PASCAL, C) are statically scoped. Current philosophy is that static scoping is a win, since if you are defining a function using a free variable x in the body like this, you usually mean the current value of x in effect where the function is defined, which you know something about, not the value where it is called, which you may not know anything about. ---------------------------------------------------------------------- The substitution model was based on the idea that you could REPLACE EQUAL EXPRESSIONS WITH EQUAL EXPRESSIONS If 'state' is defined as 0, you could replace 'state' by '0' and all is well. a concept known as REFERENTIAL TRANSPARENCY. set! destroys referential transparency -- well really, it changes what expressions are equal in all contexts. Just because 'state' equals '0' in some context, does not mean that that they will continue to be equals in all contexts. Instead, a set! may intervene and change the fact that they are no longer equals. ---------------------------------------------------------------------- We're going to introduce a NEW evaluation model, called the ENVIRONMENT MODEL * Extension of the substitution model * More "operational" - That means, closer to how the computer actually does things. But still not what it really does. - If you really want to know, CS314 will tell you An expression only has a value with respect to an ENVIRONMENT * which tells the values of the variables. * fully explains static scoping and the process by which variable names are resolved in Dylan. ANALOGY TO REAL LIFE: * Names (=words) have multiple bindings (=meanings) depending on where you are. BOOT: * Computer lab -- restart a computer * Shoe store -- thing to sell * Parking ticket -- nasty thing clamped on the wheel of your car * England -- trunk of your car * Dartmouth -- popular activity at frat parties ---------------------------------------------------------------------- Definitions: An ENVIRONMENT is an association of names with values: * An ordered sequence of one or more FRAMES where a FRAME is an (unordered) set of BINDINGS, no two with the same NAME where a BINDING is an association of a VALUE to a NAME - written NAME:VALUE Here are three frames, in order, hence an environment (one or more frames in sequence) +------------------------------------+ | x:10 +: {Proc ...} | | y:20 | | z:30 | +------------------------------------+ ^ | +------------------------------------+ | x:() | | w:'foobar | | | +------------------------------------+ ^ | +------------------------------------+ | x:'oh | | y:'(list of stuff) | | | +------------------------------------+ The value of a name is *always* determined with respect to *some* environment. * We're going to have new rules for eval and apply, with respect to environments. * Extending the substitution model rules. LOOKUP RULE: * The value of a name is the value associated to that name in the FIRST (lowest) frame with a binding for it. * It is undefined if there aren't any Example of Lookup Rule: If the environment is that one above, the value of x is oh * since the frame with x:oh is first the value of w is foobar * no binding in first frame Note: the old value of x is *shadowed* by the new one. ---------------------------------------------------------------------- define rule: Evaluating a top-level DEFINE expression adds a binding to the GLOBAL ENVIRONMENT (the top-level frame, which is special because it persists "forever"). Skips over lower frames. >>> global frame = top one <<< BEFORE: top frame is: +------------------------------------+ | x:10 +: {Proc ...} | | y:20 | | z:30 | +------------------------------------+ AFTER (define (d ) (+ 5 7)) +------------------------------------+ | x:10 +: {Proc ...} | | y:20 d: 12 | | z:30 | +------------------------------------+ Note that define only alters the top-level frame. ---------------------------------------------------------------------- SET! rule: Evaluating (set! var newval) in an environment * Look up where the value of `var' lives using lookup rule * Change that binding to be `newval' (set! x 'otter) lowest frame is now +------------------------------------+ | x:otter | | y:(list of stuff) | | | +------------------------------------+ Error if the variable isn't found. More on the environment model next time.