Recalling some structures from early lectures:
(define-struct cat (name age high?)) ;; a cat is: ;; (make-cat <symbol> <num> <boolean>) ;; where age is in months. ; Examples: (define hyde (make-cat 'bartok 9 true)) (define cat2 (make-cat 'freddy-kruger 83 false)) ;; sneak: cat --> cat ;; Returns a new cat, which is like a-cat, except that ;; it is exposed to catnip (regardless of whether a-cat was). ;; (define (sneak a-cat) (make-cat (cat-name a-cat) (cat-age a-cat) true)) (sneak hyde) = hyde (sneak cat2) = (make-cat 'freddy-kruger 83 true)
The way the world works is not that sneaking into the toy closet destroys the old cat and creates a new cat with many similar attributes. (This is perhaps a very Zen way of looking at things: "the cat you once had is no more; there is only the cat of the current moment, playfully gnawing at your ankles.")
Really, we think of it being the same cat, only that it has been modified over time. This has been a major exception to our motto "your program mirrors your thinking of the problem". We now introduce a way to really model this after all (but our world is going to get more complicated; we deferred until now to explore the richness of the more limited world, before moving on):
hyde (set-cat-high?! hyde true) hyde (set-cat-name! hyde 'Pumar-Lord-Of-The-Urban-Jungle) hydeWrite a function
grow-cat!
,
which takes in a cat, and returns the same cat a month older.
grow-cats!
, which takes in a list of cats.
If Elizabeth Windsor dyes her hair, what happens to the queen of england?
She has purple hair too!
(define hyde (make-cat 'bartok 9 true)) (define jekyll hyde) (set-cat-age! hyde 10) jekyll ; A cat w/ age 10.jekyll and hyde are two different placeholders that represent the same underlying structure. (One student that changing jekyll wouldn't change hyde, because of the order defined, but that isn't so:)
(set-cat-age! jekyll 11) hyde ; A cat w/ age 11.Both placeholders really do both refer to the same. What is the relation between hyde and some other cat named 'bartok, 11 months, who is high -- is that the same underlying cat, or is it an entirely different cat that just happens to look alike on the outside? (Hopefully the latter, since that better reflects the real world.)
How, exactly, does this work? The law-of-scheme as we know it doesn't explain this. Let's try the law-of-scheme as it stands. Think about what happened at each step. From the top:
(define hyde (make-cat 'bartok 9 true)) (define jekyll hyde) ; The placeholder hdye gets replaced with its defined value: = (define jekyll (make-cat 'bartok 9 true)) (set-cat-age! hyde 10) = (set-cat-age! (make-cat 'bartok 9 true) 10) = ; ?? Nothing returned; we expected?: (make-cat 'bartok 10 true) jekyll ; Law of scheme for placheholder says ; to look up its define'd value, which was (make-cat 'bartok 9 true) = (make-cat 'bartok 10 true) ; Uh-oh, not its defined value! ;Furthermore, we have another mystery: (set-cat-age! jekyll 11) = (set-cat-age! (make-cat 'bartok 10 true) 11) ; Evaluate placeholder "jekyll" = ; ?? Nothing returned; we expected?: (make-cat 'bartok 11 true) hyde ; Again, last we saw, hyde stood for a cat of age 10, but: = (make-cat 'bartok 11 true) mysterious!Clearly the law of scheme as we understood it, doesn't account for what we're seeing. What exactly is the mechanism, so that both refer to the same underlying cat?
Here is the truth:
Whenever you call make-cat
(or any make-[struct]
-- including
cons
, or
(make-
, build-
)vector
)
what gets returned is not a box with those entries,
but actually a reference to a box with those entries.
A reference is a new type of value.
We'll indicate references with arrows (on the chalk board),
or with hat-variables (in text):
(define hyde (make-cat 'bartok 10 true)) = (define hyde hyde^)where hyde^ is a value; that is hyde^ is a valid thing for a function to return. make-cat actually did two things: it (a) created a cat (a box with three drawers named "age", ...), (b) returned a reference to that box. We'll draw this on the board as:
Cat: +==================+ # name: 'bartok # # ~~~~~~~~ # # age: 10 # # ~~~~~~~ # # high?: true # # ~~~~~~~ # +==================+ ^ | (define hyde ---/ )Well, it gets unwieldy to draw those boxes, so we'll write the box as
(make-cat 'bartok 10 true)
, as ever.
And rather than repeatedly drawing arrows which point off to
the box, we'll write (define hyde^ (make-cat 'bartok 10 true))
.
Thus we'll write the entire above picture as:
(define hyde^ (make-cat 'bartok 10 true)) ; hyde^ is a signpost to this make-cat (define hyde hyde^) ; The value of hyde is a signpost to that make-cat.In a nutshell: Reference values are an abstract concept; to depict them we'll choose either of:
hyde
and jekyll
were clearly
the same underlying cat (we just had two different wasys of referring
to it).
Example: a hand-evaluation
(define liz (make-person 'elizabeth-windsor 'grey)) (define queen liz) (set-person-haircolor! liz 'blue) (person-haircolor queen)When we evaluated the following in lecture, we had a series of pictures (about six of them -- but i kept drawing on top of the previous picture). Here is the full hand-evaluation, where each "picture" is instead a list of define's and expressions. We won't harp on these full hand-evaluations (which now consist not of a single expression, but a list of several defines/expressions), but you should be clear on what's happening, and how it still follows the law-of-scheme.
; We're about to start evaluating all this: (define liz (make-person 'elizabeth-windsor 'grey)) (define queen liz) (set-person-haircolor! liz 'blue) (person-haircolor queen) = (define liz^ (make-person 'elizabeth-windsor 'grey)) (define liz liz^) ; We just evaluated the first "define liz..." above. (define queen liz) (set-person-haircolor! liz 'blue) (person-haircolor queen) = (define liz^ (make-person 'elizabeth-windsor 'grey)) (define liz liz^) (define queen liz^) ; It was easy to define queen -- just look up value of placeholder "liz", ; which is liz^. (set-person-haircolor! liz 'blue) (person-haircolor queen) = (define liz^ (make-person 'elizabeth-windsor 'grey)) (define liz liz^) (define queen liz^) (set-person-haircolor! liz^ 'blue) ; Again look up value of "liz", which is ; the reference "liz^" (person-haircolor queen) = (define liz^ (make-person 'elizabeth-windsor 'blue)) (define liz liz^) (define queen liz^) ; set-person-haircolor! returned nothing, but note the above side effect. (person-haircolor queen) = (define liz^ (make-person 'elizabeth-windsor 'blue)) (define liz liz^) (define queen liz^) (person-haircolor liz^) ; Evaluating placeholder "queen" easily gave "liz^" = (define liz^ (make-person 'elizabeth-windsor 'blue)) (define liz liz^) (define queen liz^) 'blue ; Easy to evaluate person-haircolor -- just follow the ; reference, and peek inside that structure.Note that each step was very small -- just evaluating a placeholder (which means finding what it was defined as, same as it always has been), or making/setting/accessing a structure.
This bit about using references to structures, rather than immediate structures, may seem like a bit of superficial syntactic wordplay, but it makes a huge difference. What if we'd said:?
(define liz (make-person ...)) (define queen-of-england (make-person ...)) (set-person-haircolor! liz 'purple)Note that references are created whenever you make a structure, even if you don't associate a placeholder with it. In fact, it's an easy observation: there is exactly ne unique structure created, for every call to
make-structure
.
Here is another (slightly shorter) review of law-of-scheme, aimed at labbies.