TEACH WHYSYNTAX Chris Mellish October 81 revised, Mark Keefe January 86 In this demo, we will consider some of the limitations of ELIZA-like programs, and how we can improve on them by producing programs that know rather more about the structure of linguistic utterances. If you haven't already done so, you should work through HELP * ELIZA and play around with the POP-11 ELIZA program before you read this demo. We will be meeting some rather useful extensions to the basic POP-11 matching abilities, and you should also make sure that you are familiar with the contents of HELP * LISTS. ---- ELIZA IS LIMITED IN VARIOUS WAYS ------------------------------------- If you have played with ELIZA at all, you will no doubt have been frustrated by some of the rather stupid responses the program can give. For instance, you might have seen interactions like the following: eliza(); hello what is your problem? ? i hate computers have you just had a bad experience with computers? .......... .......... ? i hate to wash the dishes have you just had a bad experience with to wash the dishes? From your experience of writing ELIZA-like programs, you should be able to see what could be going wrong in examples like this. Here it looks as if the program is responding to a pattern like stimulus: [i hate ??x] with the response response: [have you just had a bad experience with ^^x?] This works all right when X matches the phrase [COMPUTERS], but it is completely wrong when X matches [TO WASH THE DISHES]. How could we fix this? Whatever approach we take, it would obviously be good to have the response come out after any of: ? i hate tall women ....... ? i hate university lecturers but not after: ? i hate to sound stupid ---- SIMPLE PATTERN MATCHING IS INADEQUATE ------------------------------- Somehow, we cannot adequately describe the phrases for which the "Have you just had a bad experience with ....?" response is appropriate using just simple matching. Why is this? The main reason seems to be because the basic matching operations simply do not know anything about what English words mean or what their functions are. All the basic matching operations can take into account is the sequence of WORDS in the pattern and the utterance and whether a correspondence can be built up between them. So all we can say is things like: "any number of arbitrary words can appear here" [... ??x ...] "some particular word must appear here" [... apple ...] As we have seen, this is not good enough. The words that must appear in the "X position" of [I HATE ??X] for the response to be appropriate CANNOT be just "arbitrary words". Some sequences, like "computers", "university lecturers" do work, but others, like "to clean my teeth" and "to sound stupid" do not. --- BOOLEAN PROCEDURES ALLOW US TO SPECIFY MORE INTERESTING PATTERNS --- The way that we can specify more stringent requirements in POP-11 patterns is by using BOOLEAN PROCEDURES. Let's start with a simpler example of this. Consider the following possible ELIZA strategy: stimulus: [i am ??x] response: [i am sorry you are ^^x] In this example, we really want to impose more conditions on what X can be. For instance, this kind of sympathetic response would be all right if the "patient" said "I am bored" or "I am terribly depressed", but would be very strange if he said instead "I am delighted" or "I am really happy". The extra requirement to impose is that the phrase should describe some generally unpleasant state. Only then would sympathy be appropriate. The first stage in formulating a pattern to capture this requirement involves writing a POP-11 procedure to determine whether a list of words (such as the value of X here) does indeed describe an unpleasant state. This we will now do. --- DEFINING A BOOLEAN PROCEDURE --------------------------------------- Let's look at how we might write a program in POP-11 to determine whether a list of words does indeed describe an unpleasant state. In the absence of any deep theories about the meanings of words, we will just have to write an approximation to the ultimate "unpleasant state interpreter", cataloguing certain common phrases that do indeed describe unpleasant states. Here is a procedure of this form: define unpleasant(phrase) -> yesno; vars x; if phrase matches [bored] or phrase matches [at the end of my tether] or phrase matches [terribly ??x] then true -> yesno else false -> yesno endif enddefine; Notice the structure of this procedure. It takes a single argument (PHRASE), which is the list of words on which it is performing a test. It also produces a result (whatever is the value of YESNO when the instructions have been finished). There are three lines in the definition talking about matching conditions. The conditions are: phrase matches [bored] phrase matches [at the end of my tether] phrase matches [terribly ??x] These are linked together by the word OR. The idea is that the results of the three matches are "brought together" to make one overall truth value to express whether the phrase expresses an unpleasant state. A phrase is talking about an unpleasant state if it is "bored" OR if it is "at the end of my tether" OR if it is of the form "terribly ...". If any one of these conditions is "true", then the overall truth value for the IF condition is also "true". So the THEN actions will be carried out and YESNO will get the value "true". Otherwise the value for the IF condition is "false" and YESNO will get the value "false". Notice that in both cases we actually give YESNO the value of another VARIABLE (TRUE or FALSE). This is OK, because TRUE and FALSE are already introduced when you come into POP-11, and they have the truth values "true" and "false" respectively. Of course, UNPLEASANT contains a very incomplete catalogue of unpleasant state phrases and is maybe not even partially adequate. Nevertheless, it is a perfectly good POP-11 procedure and will do for our purposes. -- BOOLEAN PROCEDURES ARE PROCEDURES WITH TRUTH VALUES AS RESULTS ------ Let us digress briefly to consider the idea of truth values as procedure results. Normally, truth values that are worked out are immediately "used up" by conditional statements. For instance, when we write: if phrase matches [i hate ??x] then .... we expect a truth value to be produced for whether PHRASE actually does match the pattern. This truth value is immediately used to determine what to do next in the program. In the UNPLEASANT procedure, we explicitly produce a truth value as a result. This must be used by whichever procedure calls UNPLEASANT in the first place. We can finally "use up" the truth value by saying something like: if unpleasant(x) then .... or by another method which we will come to. It would be a good idea, to make sure that you understand how to write and use a procedure like UNPLEASANT, to type in the above definition or a similar one (storing it in a file) and practice using it in various situations. For instance: unpleasant([my dog has fleas])=> unpleasant([bored])=> unpleasant([terribly bored])=> unpleasant([terribly excited])=> We have called UNPLEASANT a BOOLEAN PROCEDURE. This is because it is a procedure that produces "true" or "false" as its result. The word BOOLEAN comes from the name of George Boole, a mathematical logician who worked in the 19th Century. Other Boolean procedures that you may have come across in POP-11 are MATCHES, =, ISINTEGER and <. ---- SUMMARY SO FAR ------------------------------------------------------- A quick summary of where we are. We want to be able to improve the performance of a program like ELIZA by allowing it to be more discriminating about the utterances to which it makes certain responses. We saw that silly responses were easy to generate because simple matching could not distinguish between good and bad phrases for this purpose. We also wrote an example (UNPLEASANT) of a BOOLEAN PROCEDURE, hoping that it could eventually be used in an ELIZA program. By BOOLEAN PROCEDURE here, we just mean any procedure that produces "true" or "false", according to whether some condition is true or false. For instance, UNPLEASANT is a Boolean procedure. It can be given any phrase and will answer "true" or "false" according to whether it thinks that the phrase describes an unpleasant state. ---- USING BOOLEAN PROCEDURES IN AN ELIZA PROGRAM ------------------------ How can we use Boolean procedures in an ELIZA program? One way of using them may have already occurred to you. If our original program contains the fragment: if utterance matches [i am ??x] then [i am sorry you are ^^x]=> .... then we can make it more discriminating by changing this fragment to something like: if utterance matches [i am ??x] and unpleasant(x) then [i am sorry you are ^^x]=> .... Here we are using a complex conditional using AND. We saw in UNPLEASANT how we can specify some overall truth value that depends on a number of simpler conditions using OR. AND is just the same, except that this time the overall truth value is only "true" if ALL the tests also come out "true". So here the "I am sorry ..." message will only appear if the person's remark matches [I AM ??X] AND the value of X (as set by the matching operation) is an "unpleasant" phrase. - BOOLEAN PROCEDURES CAN BE USED AS RESTRICTION PROCEDURES IN PATTERNS - POP-11 actually allows you to use Boolean procedures in matching in a more convenient way. We could have written the above example much more concisely as: if utterance matches [i am ??x:unpleasant] then [i am sorry you are ^^x]=> .... Whenever you mention a ?? variable in a POP-11 pattern, an extra condition can be placed on what kind of phrase can match there in the following way. This extra condition takes the form of a Boolean procedure that RESTRICTS what possible matches are allowed. We say that the procedure is being used as a RESTRICTION PROCEDURE in the pattern. Here's how you use a restriction procedure. Where previously you put ?? and a variable name, now you put: ?? ) As before the variable name ) : ) These are new the name of a restriction procedure ) (Of course, you can squash them up on one line, as above). ---- WHAT DOES THIS MEAN? --------------------------------------------------- What does it mean when we mention a restriction procedure in a pattern in this way? Say we indeed write a program that at some point goes: if utterance matches [i am ??x:unpleasant] then ... ... This will make sense when UTTERANCE (a variable) has got some appropriate value and we want to determine whether that value is of a certain form. The basic idea is that the match will succeed if the value is a list starting with the words [I AM], and that the variable X will receive whatever words come after that in the list (just as if we had ??X on its own there). However, by specfifying a restriction procedure (UNPLEASANT), we make one extra requirement for the match to succeed. After X has been given a value, we require that the call: unpleasant(x) returns the result "true". Otherwise we will not allow the match to succeed. Notice that in this context UNPLEASANT HAS to be the name of a Boolean procedure. It also has to be a procedure that expects EXACTLY ONE argument (because we are going to call it with X). It is not allowable to specify anything other than a procedure of this form after a variable name and a colon in a pattern. A mishap will be caused if an appropriate definition of UNPLEASANT has not been given by the time the pattern is matched. Remember: in order to be used as a restriction procedure, a procedure must expect a single item as an argument and produce a truth value as its result. Each restriction procedure we will use here will in fact all be a procedure which, given a list of words as its argument, produces a value "true" or "false". It does this according to whether the list satisfies some test. A restriction procedure can be seen as the procedural embodiment of a property (like "unpleasant" or "longer than 3 words"). ---- EXERCISE --------------------------------------------------------- Before you read any further, try defining something that could serve as a restriction procedure yourself. For instance, you could define a procedure PLEASANT (to test whether a phrase talks about a pleasant state of affairs), along the same lines as UNPLEASANT. When you have done this, try it out in some matches by typing things like: [i am happy] matches [i am ??x:pleasant] => [i am terribly depressed] matches [i am ??x:pleasant] => [happy is the name of my rabbit] matches [??x:pleasant ??y] => [john was overjoyed yesterday] matches [??x ??y:pleasant ??z] => Typing lines like these will cause the POP system to type out "true" or "false" according to whether the matches succeed. When they do succeed, it is worthwhile looking to see what values the appropriate variables (X, Y and Z) have afterwards. -- Testing for a single word ------------------------------------------ It is probably worthwhile to remember at this point that PATTERN VARIABLES in MATCHES expressions can be ditinguished by "?" as well as "??". Recall that when a PATTERN VARIABLE is preceeded by "?", as in [I am happy] matches [I am ?x] the variable can take only take on the value of a single item, rather than a list of items (TEACH *MATCHES) and it is subsequently assigned the value of the matching item, rather than a list containing the values of all the matching items. In the above example, "x" is assigned the word "happy" as its value. This will be of use to us later since we will frequently want to test a phrase, for example, to determine whether it begins with some particular type of adjective. RESTRICTION PROCEDURES can be used after "?" variables in the same manner as after "??" variables. Everything we have said above about restriction procedures still applies, however when "?" is used in front of a pattern variable, we must remember that the variable does not necessarily contain a list (it may contain a word as above) so the restriction procedure may have to use some other BOOLEAN PROCEDURE than MATCHES to test the variable. Remember, any procedure (even your own) that returns only TRUE or FALSE as results is acceptable as a restriction procedure. Suppose you know that you want to "accept" any phrase of the form: I am happy, cheerful, dreamy, etc. Then you could define a restriction procedure PLEASANT using MEMBER as follows (HELP MEMBER): define pleasant(word) -> yesno; member(word, [happy, cheerful, dreamy]) -> yesno enddefine; Try this out with the following: [I am dreamy] matches [I am ?x:pleasant] => x => [I am depressed] matches [I am ?x:pleasant] => ---- DESCRIBING APPROPRIATE ELIZA RESPONSES ---------------------------------- Let us return to our original problem: selecting an appropriate response to an utterance of the form: [i hate ??x] We saw that the appropriate response depended on what value X actually got as a result of the match. The response [have you just had a bad experience with ^^x] was only appropriate in some cases (when X was [COMPUTERS], but not [TO WASH THE DISHES]). Let's formulate this in terms of restriction procedures. If the reply is appropriate for some values of X but not others, there must be some property of phrases that applies to the good values and does not apply to the bad ones. For instance, we might conjecture that the good phrases all contain exactly one word, but the bad ones do not, or that the first letter of the first word of a good phrase always comes before "m" in the alphabet (I don't actually believe any of these!). Whatever the property is, once we have pinned it down, we ought to be able to write a restriction procedure that tests for that property being present. So eventually we should be able to write an improved ELIZA that includes a bit of program something like: if input matches [i hate ??x:mytest] then [have you just had a bad experience with ^^x]=> ... where MYTEST is the name of some procedure that needs to be defined. -- DESCRIBING "GOOD" PHRASES FOR THIS EXAMPLE -------------------------- Now for the problem of defining MYTEST. What is it that all the "good" phrases for this example have in common? A clue is given by the output sentence in which these phrases have to be used. What kind of phrases can be stored in X for the list: [have you just had a bad experience with ^^x] to represent a plausible sentence? Well, here's a possible start that will get us quite a long way. A phrase of the form "experience with ..." usually only makes sense if we are talking about experience with some specific thing(s). "Experience with computers" makes sense because computers are things. Similarly, "experience with tall women" and "experience with university lecturers" all make sense, because tall women and university lecturers are also things. However, "experience with to wash the dishes" makes no sense, because the sequence of words "to wash the dishes" is not talking about things in at all the same way. ---- PHRASES TALKING ABOUT THINGS ------------------------------------ How can we write the procedure MYTEST so that it says "true" when it is given a phrase talking about a thing and "false" otherwise? One obvious way is for the procedure to compare the phrase with each of a long list of examples, as UNPLEASANT did. So we could write: define mytest(phrase) -> result; if phrase matches [computers] or phrase matches [tall women] or phrase matches [university lecturers] or phrase matches [boring lecturers] or .... then true -> result else false -> result endif enddefine; This method is very laborious and neglects the fact that there is important STRUCTURE in common between a large class of phrases that talk about things. For instance, we can talk about "tall women", "short women", "brave women", "mean angry women" and so on. All these phrases are talking about kinds of women. We can tell this just from the last word - "women" in each case. This single word says immediately what class of objects we are discussing, and the other words merely serve to narrow our attention to some restricted part of the class. The word "women" is called a NOUN - a word that "names" some class of objects. The words "computers" and "lecturers" are also nouns. These nouns are all in the PLURAL form - we are talking about more than one member of the class in these examples. The corresponding SINGULAR forms of these nouns are "woman", "computer" and "lecturer" and are used when we are talking about one member of the class at a time, as in "I hate the Cognitive Studies computer". Nouns are important, because a large number of phrases that talk about things actually contain nouns. In fact, we will be looking at a class of phrases where nouns play a central role - these are called NOUN PHRASES. ---- A FIRST DESCRIPTION --------------------------------------------- As a second step towards a sensible definition of MYTEST, we could decide that we will say that any phrase containing a noun should pass the test. Our second definition will look something like: define mytest(phrase) -> result; vars x,y,z; phrase matches [??x ?y:noun ??z] -> result enddefine; This is not yet complete, but notice what we have done here. In order to test whether a phrase is talking about a thing or things, we are using the matcher again to see whether the phrase is of a certain form. Notice that there is only a single '?' before NOUN. This is because verbs are a 'lexical category' and hence are only a single word. Noun phrases are a 'syntactic category' and so can be any number of words so we must use a double query, ie '??'. As part of the pattern, we have specified that a certain lexical category (to be stored in the variable Y) satisfies another restriction procedure, NOUN. We must, of course, define noun so that it tests whether a phrase is a noun and returns "true" or "false" accordingly. That we will do in a moment. But first, note that the procedure MYTEST will itself be used as part of a matching operation to determine what reply should be made to the latest utterance. So when our (mythical) ELIZA program gets to use this definition, what will actually be happening will be something like the following: ELIZA definition uses ... (to determine next response) MATCHES, which uses... (to try pattern [i hate ??x:mytest]) MYTEST, which uses... (to see if the phrase has a noun) MATCHES, which uses... (to try pattern [??x ??y:noun ??z]) NOUN This is nothing to be worried about. There is nothing wrong in procedures calling other procedures calling other procedures..... and so on for as long as we like (although we have to be a bit careful when a procedure indirectly calls ITSELF). ---- DEFINING "NOUN" ------------------------------------------------------- Now for the definition of NOUN. Unfortunately, this will have to detail all the nouns that we know about - a lengthy business that we won't bother to finish properly here. Neverthless, it is somewhat shorter than detailing all the possible phrases that talk about things - there are many fewer of them. Here's a start towards a definition of NOUN: define noun(word) -> isit; member(word, [cat, dog, computer, computers, ... ]) -> isit enddefine; In general, if we expect to be constructing programs that handle language intelligently, we will have to tell them about whole collections of words. One thing to say about each word is the grammatical category (like "noun") to which it belongs. We might organise this information by making (potentially) very long procedures, like the above attempt at NOUN. On the other hand, we might like to think of there being some central store of information (called a DICTIONARY) about individual words. For instance, we could keep a dictionary by having facts like: [cat noun] [computer noun] .... in the database. With a more ambitious program, we might store some representation of a word's MEANING in the dictionary as well. Another important thing to know about words is information about their MORPHOLOGY - that is, how the exact form of a word changes according to the context. We talked above about the singular and plural forms of nouns. Ideally, we would only need one dictionary entry for all the words: computer, computers, computer's, computers' (and maybe more...) This entry would have to indicate how the word may appear in different forms in different places. Most words change their shape according to quite simple rules. ---- THE FIRST SOLUTION IS INADEQUATE ---------------------------------------- Given (possibly incomplete) definitions of MYTEST and NOUN, we are now in a position to offer a first solution to the problem: when is the sequence: stimulus: [i hate ??x] response: [have you just had a bad experience with ^^x?] appropriate? The solution is: when the phrase in X contains a noun. Unfortunately, this solution will allow through precisely the example we saw where the response is NOT appropriate! If the person says: i hate to wash the dishes then the variable X will get the list [TO WASH THE DISHES]. This list does indeed contain a noun - the word "dishes". (The word "wash" can also be a noun, although it is used as another part of speech here). So our program will continue to make an inappropriate response to this utterance. ---- CAPTURING THE NOTION OF "NOUN PHRASE" MORE PRECISELY ------------------ The trouble with our existing description of a phrase talking about a thing is that it is too loose - it also applies to any larger phrase that contains a phrase talking about a thing! Let us try to pin down more precisely the class of phrases which are centred around nouns - so called NOUN PHRASES. We must give some description that will enable a program to tell where a noun phrase begins and where it ends. As a first approximation, we could say that a noun phrase should always END with a noun. This is the case with all the noun phrases we have come across so far, although we might want to generalise it later. So much for the end of a noun phrase, but what about the words before the noun? We saw that words like "mean", "angry" and "tall" can appear before a noun. These words are called ADJECTIVES. We could define a procedure ADJECTIVE to recognise one of these exactly as we did with NOUN. So a noun phrase may have an adjective before the noun. Can anything come before this? There is another class of words, called DETERMINERS, that can come before adjectives and mark the start of a noun phrase. These are words like "the", "each", and "my". ---- PUTTING THIS INTO A PROGRAM ---------------------------------------- Let's embody this improved notion of what a noun phrase is in a program. This program will replace MYTEST by providing a stricter test for "nounphraseness". So let's call it NOUN_PHRASE. Here's how we can start to write it: define noun_phrase(phrase)-> trueorfalse; vars x, y, z; phrase matches [?x:det ??y:adjs ?z:noun] -> trueorfalse enddefine; This definition makes use of two new restriction procedures, DET and ADJS, which will themselves have to be defined. According to this definition, a phrase is a noun phrase if it consists of three parts. The first (X) must pass the test for being a determiner. The second (Y) must pass the test for being a number of adjectives. The third (Z) must pass the test for being a single noun. DET is to be a procedure that recognises a determiner (just like NOUN recognises a noun), and you might like to define a version of this yourself (look at the NOUN definition to see what kind of form the definition can have). ADJS is rather more interesting. We saw before that a noun phrase can contain ANY NUMBER OF adjectives (for instance "the big hairy angry lumbering gorilla"). So we need to have a test that takes this into account. ---- DEALING WITH ALTERNATIVES ------------------------------------ Let's consider how we can define ADJS. Let's assume that we can at some stage define a simpler procedure ADJ, which recognises a single adjective (this will be defined very much like NOUN). We will need to use ADJ in the definition of ADJS. Now ADJS is supposed to return "true" or "false" depending on whether the phrase it is given is a string of adjectives. The definition is going to be complicated by the fact that the result should also be "true" if the phrase is a string of ZERO adjectives - that is, if the phrase has no words in it. We have to provide for this case. Otherwise we couldn't say that the phrase "the man" was of the form DET followed by ADJS followed by NOUN, as we would like. So there are two cases to be looked for. A phrase is of type ADJS if EITHER it consists of one or more adjectives OR it is an empty phrase. We can express these two possibilities by using OR in the definition: define adjs(phrase) -> isitso; if ....one or more adjectives.... or ....empty phrase.... then true -> isitso else false -> isitso endif enddefine; where the bits between dots are to be filled in. The test for the empty phrase is easy - we just have to see if the phrase matches []. What about the other case? Can we give a pattern for that? Well, whatever else is in it, such a phrase must start with an adjective. So our definition now looks like: define adjs(phrase) -> isitso; vars x; if phrase matches [?x:adj ...something...] or phrase matches [] then true -> isitso else false -> isitso endif enddefine; Now what should "...something..." be? If the whole phrase consists of exactly one adjective, then "...something..." must match the empty phrase. Alternatively, if the phrase has more than one adjective, then "...something..." must match a phrase with one or more adjectives. This ought to be sounding rather familiar. In fact, this is exactly the criterion we used for determining what phrases ADJS itself should accept. So we can use ADJS inside its own definition: define adjs(phrase) -> isitso; vars x, y; if phrase matches [?x:adj ??y:adjs] or phrase matches [] then true -> isitso else false -> isitso endif enddefine; ---- SUMMARY OF PROCEDURES ---------------------------------------- By now, we have developed (or hinted at how to develop) a number of procedures to be used in an ELIZA program. Each of these can be used as a RESTRICTION PROCEDURE, that is, it tests whether something satisfies a given condition and returns the value "true" or "false" accordingly. In fact, each of these is designed to test for a particular kind of English phrase, as follows: NOUN_PHRASE - a noun phrase, eg. "the noisy balloon" NOUN - a noun, eg. "monkey" or "bananas" ADJ - an adjective, eg. "funny" or "red" DET - a determiner, eg. "the" or "any" ADJS - a sequence of (possibly no) adjectives, eg. "" or "noisy filthy" All of these were developed as part of the enterprise of defining NOUN_PHRASE. The reason for defining NOUN_PHRASE was so that we could provide a better pattern to determine when a particular ELIZA response was appropriate. Given the existence of these procedures, we can have a piece of program that goes: if input matches [i hate ??x:noun_phrase] then [have you just had a bad experience with ^^x] => ... and we will know that this response will (almost) always be given only when it is more or less appropriate. Indeed, we can even improve on this to get: if input matches [i hate ??x:noun_phrase ??y] then [have you just had a bad experience with ^^x]=> ... This bit of program will even produce a sensible response to "I hate gooseberries, they are so bitter". (What will the response be?) ---- WHERE DOES THIS LEAD? ---------------------------------------- In working through these examples, we have found that a really good ELIZA is going to have to know something about the STRUCTURE of English utterances - about what kinds of phrases there are and how a phrase divides up into subphrases. When we talk about utterances in this way, we are discussing the SYNTAX of the language concerned, here English. Traditionally, the syntax of a language is expressed by means of a GRAMMAR, which is a formal description saying what kinds of sequences of words are grammatical and what kinds of sequences are not. In these examples, we investigated briefly the grammar of noun phrases. We said that a noun phrase had to consist of a determiner followed by some number of adjectives and then a noun. A linguist would express this piece of grammatical knowledge something like this: noun_phrase --> det adjs noun adjs --> adj adjs adjs --> The procedures we have defined are capable of telling whether something is a noun phrase according to the criteria of this small grammar. In doing so, they are also determining what the structure of a particular noun phrase is - which word is the DET, which words are the ADJS, etc. We could imagine building a program that built some kind of description of the structure of a phrase as it found it. Such a program would be called a PARSER. The question arises - would such a description be of any use? The answer that many people would give is: Yes, a description of the syntactic structure of an utterance is of fundamental importance for determining the meaning of the utterance in a principled way. The existence of computer programs capable of building such descriptions leaves the way open for a generation of language understanding programs that go significantly beyond ELIZA in their generality and usefulness...... ---- RELEVANT BACKGROUND READING ------------------------------------------- Boden, M. "Artificial Intelligence and Natural Man", Chapters 5 and 6. Schank, R. and Colby, K. "Computer Models of Thought and Language". Article by T. Winograd TEACH * GRAMMAR - Generating and analyzing sentences After this try TEACH * ISASENT - Recognizing english sentences