Suggestions for programming the ELIZA assignment

Note: This page is meant as hints and suggestions, not as additional requirements. Feel free to ignore this page if you've already found another way to do the assignment.


People are having trouble trying to use I/O in this assignment. I haven't actually said much about I/O, because it's complicated and not well standardized. It's easier if you don't do your own input, but use a couple of LISP tricks to do the input and output for you.

There are two easy kinds of I/O:

Here's how I would go about writing the program. Again, these are suggestions, not requirements.

To "talk" to Eliza, write a function say that takes one argument, which is a list of words, and returns Eliza's response as its result. This way, you don't have to do any input/output at all. For example:

CL-USER 1 > (say '(men are all alike))
(IN WHAT WAY)

CL-USER 2 > (say '(they're always bugging us about something or other))
(CAN YOU THINK OF A SPECIFIC EXAMPLE)

As I said in the assignment, do not worry about minor matters of syntax, such as parentheses around sentences or uppercase and lowercase letters. If it's convenient to embed sentences in function calls (as above), that's OK too.

Eliza uses "patterns," which I asked you to read in from a file. The easy way to do this is to bundle up your patterns into a function, then LOAD that function. Each time you call the function, you will get the list of patterns. For example, if your patterns are:

I remember 1 => Why do you remember 1 just now?
I feel 1 => Have you always felt 1?
How are you? => I am fine, how are you?

You might encode them in a function named PATTERNS, as follows:

(defun patterns ()
     '(  ((i remember 1) (why do you remember 1 just now))
         ((i feel 1)  (have you always felt 1))
         ((how are you)  (I am fine how are you))  )  )

Notice that the body of the function consists of a single quoted list. Each element of the list is a (pattern result) pair. The pattern and the result are each lists of words. So, for example, the first pattern is (i remember 1) and the first result is (why do you remember 1 just now). In this example I'm using the number 1 to represent a variable slot, because I can easily test if an atom is a number with the predicate numberp (and if I ever want to use more than one variable, which is not required in your assignment, I can use 2, 3, etc.) To use this function, just call it as (patterns), and it will return as its value the list (((i remember 1) (why do you remember 1 just now)) ((i feel 1) (have you always felt 1)) ((how are you) (I am fine how are you))).

In the assignment I said:

(Extra credit) "Remember" some topics that were discussed earlier, and incorporate them into your general-purpose responses: "Tell me more about your trip to Brazil."

If you want to "remember" something from one top-level function call to the next, you need a "global variable." SETQ is a special form that act like an assignment statement to a global variable. SETQ takes two arguments, an atom (which is automatically quoted) and an expression (which is evaluated), and assigns the result of evaluating the expression to the atom. Afterwards, whenever you evaluate that atom, you get the result that was assigned to it. This is just what you need for the extra credit part of the assignment. However, do not use SETQ any more than necessary; assignment is not a "natural" part of Lisp.