University of Virginia, Department of Computer Science
CS200: Computer Science, Spring 2004

Problem Set 6: Adventures in Charlottansville — Comments

Question 1: Why does (ask Cabal-Hall 'neighbor-towards 'down) evaluate to a procedure?

The neighbor-towards method evaluates to the place that is the neighbor in the requested direction (in this case, a steam tunnel). This is an object, which is a procedure.
Question 2: For each of the Scheme expressions below, predict what they will evaluate to. Then, try evaluating them in your interactions window. Write an explanation that explains clearly why evaluate the way they do. In particular, if an expression evaluates to a procedure, you should explain what procedure it is.

a. (make-object 'book)

The procedure that is the body of make-object. It starts with (lambda (message) (if (eq? message 'object?) ...) and has an environment pointer to a frame where name is bound to 'book.
b. ((make-object 'book) 'name)
The procedure that is the name method of make-object: (lambda (self) name). It has an environment pointer to a frame where self is bound to the object that (make-object 'book) evaluated to. That frame's environment pointer points to a frame where name is bount to 'book.
c. ((make-object 'book) 'fly)
Evaluates to #f since their is no 'fly method. Note that the body of the make-object procedure evaluates to #f if the passed message does not match any of the methods.
d. (((make-object 'book) 'name) (make-object 'donkey))
Evaluates to 'book.
e. (((make-object 'book) 'say) (make-object 'donkey) (list 'hello))
        Is the book talking or the donkey?
The book is talking, but the donkey is self. Since the say method doesn't actually use self this doesn't matter (although it is a bit odd, that's why we normally use ask to invoke methods and make sure the right object is always passed as self).
f. (eq? (make-object 'book) (make-object 'book))
Evalates to #f. The eq? procedure evaluates to #t only if the two operands are the same entities. That is, if you drew an environment diagram, they would be the same thing in that diagram. For two procedures to be eq?, they must be the same procedures and also have the same frame. For example, try:

> (define book1 (make-object 'book))

> (define book2 (make-object 'book))

> book1


     Note that a procedure created by a lambda is displayed as the line and column number where the procedure was made.
     In this case, line 24 of is (lambda (message).

> book2


> (eq? book1 book1)


> (eq? book1 book2)


> (eq? + +)


Question 3: The say method of make-object takes a list as its second parameter and says everything in that list. Instead of saying a whole list, we might want a method that says just one thing. Define an utter method of make-object that behaves like this:
> (define dog (make-object 'spot))
> (ask dog 'utter 'wuff)


You can use (display sym) to output one symbol. The output in this example would be produced by (display 'wuff).
(define make-object 
  (lambda (name)
    (lambda (message)
      (if (eq? message 'object?)
	  (lambda (self) #t)
	  (if (eq? message 'class)
	      (lambda (self) 'object)
	      (if (eq? message 'name)
		  (lambda (self) name)
		  (if (eq? message 'say)
		      (lambda (self list-of-stuff)
			(if (not (null? list-of-stuff))
			    (display-message list-of-stuff))
		      (if (eq? message 'install)
			  (lambda (self . args) 'installed)
			  (if (eq? message 'utter)
			      (lambda (self utterance) 
				(display utterance))
Question 4: A professor is even more arrogant than a lecturer. Define a procedure (make-professor name) that produces a professor object. It should inherit from make-lecturer, so it will be able to respond to the lecture message. It should also have a method profess that is like lecturing, but precedes every statement with “it is intuitively obvious that”.
(define (make-professor name)
  (let ((super (make-lecturer name)))
    (lambda (message)
      (if (eq? message 'profess)
	  (lambda (self message)
	    (ask self 'say (list "It is intuitively obvious that"))
	    (ask self 'lecture message))
	  (get-method super message)))))
Question 5: A student is a special kind of person (this doesn't necessarily mean all students are special or kind). Define a procedure make-student that creates a student object. It should inherit from person.

Some of the students in Charlottansville have a strange habit of getting undressed and running around the Green, so students have an instance variable is-dressesed that indicates whether or not the student is clothed. Initally, all students are dressed. The get-undressed that changes the state of is-dressed to #f. A student also has a method get-dressed that changes the state of is-dressed to #t. A student also has a method is-dressed? that evaluates to #t if the student is dressed and #f otherwise.

(define (make-student name) 
  (let ((super (make-person name))
	(is-dressed #t))
    (lambda (message)
      (case message
	((class) (lambda (self) 'student))
	((student?) (lambda (self) #t))
	((get-undressed) (lambda (self) 
			   (ask self 'say (list "brrrrr...its cold!"))
			   (set! is-dressed #f)))
	((get-dressed) (lambda (self) 
			 (ask self 'say (list "I feel much better now."))
			 (set! is-dressed #t)))
	((is-dressed?) (lambda (self) is-dressed))
	(else (get-method super message))))))
Question 6: Define a procedure make-police-officer that inherits from person. A police officer behaves differently from a person since a police office can arrest other people. So, it has an additional method: The clock-tick method for a police officer should automatically arrest anyone streaking in the same place as the police officer. If no one is streaking, the police officer will act like a normal person — that is, it should invoke the super class (person) clock-tick method. You may find the other-people-at-place procedure (defined in useful.
(define (make-police-officer name) 
  (let ((super (make-person name)))
    (ask super 'make-restless 2) ;;; Police officers are quite restless
    (lambda (message)
      (case message
	((class) (lambda (self) 'police-officer))
	((police-officer?) (lambda (self) #t))
	((arrest) (lambda (self arrestee) 
		    (if (eq? (ask self 'location) (ask arrestee 'location))
			  (ask self 'say (list (ask arrestee 'name) ", you are under arrest!"))
			  (ask arrestee 'move-to Jail)
			  (ask self 'say 
			       (list "You have the right to remain silent, call methods and mutate instance variables.")))
			(ask self 'say (list (ask arrestee 'name) " is not here")))))
	 (lambda (self) 
	   (let ((streakers (filter (lambda (person)
				      (not (ask person 'is-dressed?)))
				    (other-people-at-place self (ask self 'location)))))
	     (if (null? streakers)
		   (ask self 'say (list "No one to arrest. Must find donuts."))
		   (ask super 'clock-tick))
		 (map (lambda (streaker)
			(ask self 'arrest streaker))
	(else (get-method super message))))))
Note that the (ask super 'make-restless 2) is before the (lambda (message) .... That means it happens when (make-police-officer 'officer-krumpke) is evaluated, but does not happen every time a message is sent to the police officer.
Consider the streakability problem defined below:
Input: An initial state consisting of a set places in the Charlottansville world, a student object (as described in Question 5) and a police officer object (whose clock-tick method may contain any code).

Output: If there is any sequence of actions the student object can take to streak from the Recursa to the Bart Statue without getting arrested at any time during the game, output true. Otherwise, output false.

You should assume the results of random are completely determined (that is, you can always predict what an application of random evaluates to).

Question 7: Is the streakability problem decidable or undecidable? If you claim it is decidable, you should argue convincingly that you could define a procedure that solves it for all possible inputs. If you claim it is undecidable, you should argue convincingly that it is undecidable by showing how a solution to the streakability problem could be used to solve another problem that is already known to be undecidable.

The streakability problem is undecidable. The easist way to show this is to show that if you had an algorithm (remember that an algorithm is a procedure that is guaranteed to terminate on every possible input) that solves the streakability problem, you could use it to solve a problem that is known to be undecidable. For example, you could define halts? (that is guaranteed to terminate) using streakable? if streakable? is an algorithm that solves streakability.

Here's how:

(define (halts? P input)
   ;;; halts? evaluates to true if evaluating P on input would terminate, and
   ;;;        evaluates to false if evaulating P on input would never terminate.

   ;;; An arresting-police-officer inherits from police-officer except before
   ;;; making an arrest it evaluates (P input).  Hence, if (P input) terminates,
   ;;; the arresting-police-officer makes the arrest normally.  If (P input) does
   ;;; not terminate, the arresting-police-officer arrests before making the
   ;;; arrest, and hence never arrests anyone.

   (define (make-arresting-police-officer name)
    (let ((super (make-police-officer name)))
      (lambda (message)
	(if (eq? message 'arrest)
	    (lambda (self arrestee)
	      (P input)
	      (ask super 'arrest arrestee))
	    (get-method super message)))))

   (let ((aph (make-student 'alyssa-p-hacker)))
     (set-up-charlottansville) ;;; We'll use Charlottansville as our world
     (install-object (make-arresting-police-officer 'officer-halty) Green)
     (install-object aph Green)
     (ask aph 'get-undressed)
     (not (streakable?))))
So, on the first clock-tick message, Officer Halty will find Alyssa undressed on the Green and attempt to arrest her by invoking the arrest method of make-arresting-police-officer. If (P input) terminates, then Alyssa will be arrested. Hence, streakable? would evaluate to false and (halts? P input) should evaluate to true. It does, since we have defined halts? to evaluate to (not (streakable?)). On the other hand, if (P input) does not terminate, Officer Halty will never arrect Alyssa. Hence (not (streakable?)) evaluates to false. Thus, we have defined an algorithm for halts? assuming we have an algorithm for streakable?. But we know we cannot define an algorithm for halts? so streakable? must be undecidable.

Note that the fact that streakable? is undecidable does not mean that it is safe or unsafe to streak. For a particular world state, it may be possible to prove that there is a sequence of moves which enables a student to streak without getting arrested (or to know that the student will be arrested). The undecidability of streakability just means that it is impossible to define an algorithm that always determines this for any possible input.

[an error occurred while processing this directive]