Note that, by convention, most Scheme functions and special forms which change the state of something are named with a bang (!), e.g., set!. We'll see a couple more of these later in the course.
Try evaluating the following examples. First try them in your head or on paper. Then try them in DrScheme (or Donkey) to see if you were right.
(define x 1) (define y 2) (set! x (+ x 1)) (set! y (+ y 1)) (set! x (+ x y))What are x and y now?
(define x 5) (+ (begin (set! x 6) x) x)and
(define y 5) (+ y (begin (set! y 6) y))For each, do you get 10, 11, or 12? What does that tell you about the order of evaluation?
(define x 1) (define y 0) (local ((define x 3)) (begin (set! x (+ x 1)) (set! y x) y))What are x and y now?
Note that you don't actually need the begin here, e.g.:
(define x 1) (define y 0) (local ((define x 3)) (set! x (+ x 1)) (set! y x) y)Inside a local, there is an implicit begin.
(define x 1) (define test (lambda (x) (begin (set! x (+ x 3)) x))) x => ? (test 1) => ? x => ? (test x) => ? x => ?Note that again the begin here is optional, lambdas have an implicit begin:
(define x 1) (define test (lambda (x) (set! x (+ x 3)) x))Our rules for understanding evaluation don't make sense for this code. In Comp 311, you'll learn a more complicated set of rules that does handle it. However, we can rewrite this to something which we do understand. Let's introduce a local variable x' and use it instead of x:
(define x 1) (define test (lambda (x) (local ((define x' x)) (begin (set! x' (+ x 3)) x'))))
Being able to change state allows us to solve some problems more easily. But it can also be very confusing. One way to restrict the use of state to something manageable is to package the use of set! into objects. We'll show some simple examples for you to try in DrScheme (or Donkey). The following code is in /home/comp210/public_html/Labs/lab09/examples.ss.
Objects themselves are explained more in this week's lectures. In lab, we're more concerned with playing with a specific example. Due to time limitations, we'll mainly let you figure things out by using these objects in some suggested ways.
We model rooms and people moving around these rooms. Some of you may recognize this as the basis of almost any adventure game. Each room has at most four adjoining rooms (to the east, west, north, and south) and at most one thing in it. A person starts in some room, can move to other rooms, and carries at most one thing at a time.
(define make-room (lambda (name) (local ; local state of room object ((define thing #f) ; by default, nothing in room (define east #f) ; by default, no adjoining rooms (define west #f) ; ... (define north #f) ; ... (define south #f)) ; ... (lambda (msg) ; start of object returned (cond ((null? msg) 'badmessage) ; initialize things and adjoining rooms ((eq? (car msg) 'set-thing!) (set! thing (car (cdr msg)))) ((eq? (car msg) 'set-east!) (set! east (car (cdr msg)))) ((eq? (car msg) 'set-west!) (set! west (car (cdr msg)))) ((eq? (car msg) 'set-north!) (set! north (car (cdr msg)))) ((eq? (car msg) 'set-south!) (set! south (car (cdr msg)))) ((eq? (car msg) 'name) name) ; look at surroundings ((eq? (car msg) 'observe-thing) thing) ((eq? (car msg) 'observe-east) east) ((eq? (car msg) 'observe-west) west) ((eq? (car msg) 'observe-north) north) ((eq? (car msg) 'observe-south) south) ((eq? (car msg) 'take-thing) (local ((define x thing)) (set! thing #f) x)) (else 'badmessage)))))) (define make-person (lambda (initial-room) (local ((define thing #f) ; initially, nothing carried (define room initial-room)) (lambda (msg) ; start of object returned (cond ((null? msg) 'badmessage) ; initialize thing and room ((eq? (car msg) 'set-thing!) (set! thing (car (cdr msg)))) ((eq? (car msg) 'set-room!) (set! room (car (cdr msg)))) ; look around ((eq? (car msg) 'look-room) (if room (local ((define eastroom (room (list 'observe-east))) (define westroom (room (list 'observe-west))) (define northroom (room (list 'observe-north))) (define southroom (room (list 'observe-south)))) (list (room (list 'observe-thing)) (if eastroom (eastroom (list 'name)) #f) (if westroom (westroom (list 'name)) #f) (if northroom (northroom (list 'name)) #f) (if southroom (southroom (list 'name)) #f))) 'badmessage)) ((eq? (car msg) 'look-self) thing) ; move, if possible ((eq? (car msg) 'go-east) (if (and room (room (list 'observe-east))) (set! room (room (list 'observe-east))) 'badmessage)) ((eq? (car msg) 'go-west) (if (and room (room (list 'observe-west))) (set! room (room (list 'observe-west))) 'badmessage)) ((eq? (car msg) 'go-north) (if (and room (room (list 'observe-north))) (set! room (room (list 'observe-north))) 'badmessage)) ((eq? (car msg) 'go-south) (if (and room (room (list 'observe-south))) (set! room (room (list 'observe-south))) 'badmessage)) ; get the room's thing if any, dropping our current thing ((eq? (car msg) 'get-thing) (if (and room (room (list 'observe-thing))) (local ((define temp-thing (room (list 'observe-thing)))) (room (list 'set-thing! thing)) (set! thing temp-thing)) 'badmessage) (else 'badmessage)))))))
Each room object has two groups of messages: those for initialization and those for use after initialization. E.g., in a game, only the game designer would be able to use the initialization messages to create a maze. Here, the maze designer can decide whether corridors between rooms are two-way or not, since there is no consistency built in to the objects.
Now to create a small maze and a couple people in it:
(define room1 (make-room 'joes-office)) (define room2 (make-room 'johns-office)) (define room3 (make-room 'PL210)) (define room4 (make-room 'CS-office)) (room1 (list 'set-thing! 'ball)) (room2 (list 'set-thing! 'key)) (room4 (list 'set-thing! 'stapler)) (room1 (list 'set-east! room3)) (room1 (list 'set-north! room2)) (room2 (list 'set-south! room1)) (room2 (list 'set-west! room4)) (room3 (list 'set-south! room1)) (room3 (list 'set-north! room2)) (room4 (list 'set-east! room2)) (room4 (list 'set-west! room1)) (room4 (list 'set-north! room1)) (define joe (make-person room1)) (define john (make-person room2))
Now, you can move joe and john around:
(joe (list 'look-room)) (john (list 'go-south)) (john (list 'go-east)) (joe (list 'get-thing)) (john (list 'get-thing)) (joe (list 'look-room)) (joe (list 'look-self)) (john (list 'look-room)) (john (list 'look-self))
How would you like to enhance these objects? Some of my ideas are the following:
We will start programming in C next week, so you will start using Emacs (or some other editor of your choice) then. Make sure you can do the following: