From 562a9a52d599d9a05f871404050968a5fd282640 Mon Sep 17 00:00:00 2001 From: elioat Date: Wed, 23 Aug 2023 07:52:19 -0400 Subject: * --- js/games/nluqo.github.io/~bh/v2ch9/doctor.html | 1641 +++++++++++++++++++++ js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif | Bin 0 -> 7225 bytes js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg | 794 ++++++++++ 3 files changed, 2435 insertions(+) create mode 100644 js/games/nluqo.github.io/~bh/v2ch9/doctor.html create mode 100644 js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif create mode 100644 js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg (limited to 'js/games/nluqo.github.io/~bh/v2ch9') diff --git a/js/games/nluqo.github.io/~bh/v2ch9/doctor.html b/js/games/nluqo.github.io/~bh/v2ch9/doctor.html new file mode 100644 index 0000000..b83fccb --- /dev/null +++ b/js/games/nluqo.github.io/~bh/v2ch9/doctor.html @@ -0,0 +1,1641 @@ + + +Computer Science Logo Style vol 2 ch 9: Example: Doctor + + +Computer Science Logo Style volume 2: +Advanced Techniques 2/e Copyright (C) 1997 MIT +

Example: Doctor

+ +
+cover photo + +
Brian +Harvey
University of California, Berkeley
+

+
Download PDF version +
Back to Table of Contents +
BACK +chapter thread NEXT +
MIT +Press web page for Computer Science Logo Style +
+ +

Program file for this chapter: doctor + + + +

? doctor
+Hello, I am the doctor.  What can i do for you?
+Please end your remarks with an empty line.
+
+My spirits are low.
+
+Your spirits are low?
+
+I'm really depressed.
+
+I'm sorry to hear you are depressed.
+
+It's because nobody likes me.
+
+Really, nobody?
+
+That's right.
+
+I am not sure I understand you fully.
+
+I'm lonely.
+
+Is it because you are lonely that you came to me?
+
+Of course.
+
+Earlier you said your spirits are low.
+
+ +

This is the beginning of a dialogue with a program called doctor. The +program simulates the behavior of a psychotherapist. People who +interact with this program are often fooled into thinking that the program +understands what they are saying, although in fact the program does not +understand at all. Instead, the program recognizes certain key words in a +sentence, words like "problem" or "nobody." For each of these words, +there is a list of rules; a rule consists of a pattern (of the sort +used by the pattern matcher of Chapter 7) and a set of possible +responses. For example, associated with the word "nobody" is the pattern + +

[# !a:in [everyone everybody nobody noone] #]
+
+ +

Corresponding to that pattern is a list of responses: + +

[[Really, :a?]
+ [Surely not :a.]
+ [Can you think of anyone in particular?]
+ [Who, for example?]
+ [You are thinking of a very special person.]
+ [Who, may I ask?]
+ [Someone special perhaps.]
+ [You have a particular person in mind, don't you?]
+ [Who do you think you're talking about?]
+ [I suspect you're exaggerating a little.]]
+
+ +

The program has so many possible responses so that each time you +use the word "nobody" (or "everybody," etc.) you get a different +answer. Even though many of the answers have the same meaning, the variety +in the wording helps to convince you that it's a real person at the other +end of the conversation. + +

Many versions of this program have been written, but the first was written +in 1966 by Joseph Weizenbaum, a professor of computer science at +MIT. He called his program Eliza after Eliza Doolittle, a +character in the play Pygmalion by George Bernard Shaw. Eliza +started life poor and uneducated, with rough speech, but in the play she is +taught to speak better. The program, too, can be taught rules to help it +speak better. + +

+Because conversations must be about something, that is, because they must +take place within some context, the program was constructed in a two-tier +arrangement, the first tier consisting of the language analyzer and the +second of a script. The script is a set of rules rather like those that +might be given to an actor who is to use them to improvise around a certain +theme. Thus Eliza could be given a script to enable it to maintain a +conversation about cooking eggs or about managing a bank checking account, +and so on. Each specific script thus enabled Eliza to play a specific +conversational role. + +

+For my first experiment, I gave Eliza a script designed to permit it to play +(I should really say parody) the role of a Rogerian psychotherapist engaged +in an initial interview with a patient. The Rogerian psychotherapist is +relatively easy to imitate because much of his technique consists of drawing +his patient out by reflecting the patient's statements back to him... +

+[Joseph Weizenbaum, Computer Power and Human Reason (Freeman, 1976), +page 3.] +

+ +

+It has long been a popular Logo programming project to implement a small +subset of doctor's conversational ability through a program that embodies +directly a few of the rules in Weizenbaum's Doctor script for Eliza. (See, +for example, Harold Abelson, Apple Logo (BYTE Publications, 1982), +page 158.) Home computers now have enough memory to permit the +implementation in Logo of Weizenbaum's original two-tier approach. The +program presented here is not a line-for-line translation of Eliza into +Logo, but does embody the same fundamental strategy (namely pattern +matching) as the original. The script is a close adaptation of Weizenbaum's +version, via a Lisp version by Jon L. White. + +

You should try conversing with doctor yourself a few times. Whenever you +get a response that seems linguistically bizarre, make a note of it. Later, +as I'm talking about the way the program works, you can ask yourself how you +would modify the script to eliminate the bad responses you've noted. + +

Eliza and Artificial Intelligence

+ +

When Eliza was first unveiled, many people considered it a major advance in +the pursuit of artificial intelligence: the search for ways +to make computers as intelligent as people. Especially to a person +unfamiliar with computer programming, a conversation with the Doctor can +seem very real indeed. But as Weizenbaum himself points out, the underlying +techniques used in the program do not involve any real understanding of the +conversation. The program "cheats." + +

Today there are language-understanding programs that use techniques much +more sophisticated than the simple pattern matching of Eliza. The authors +of some such programs maintain that they really do understand what they are +saying and hearing, in a sense in which Eliza does not. Other people, +including Weizenbaum, suggest that even these state-of-the-art artificial +intelligence programs are merely cheating in more complex ways. What would +it mean for a program "really" to understand a conversation? This is a +deep question that would take too long to explore here. (I'll come back to +it in the discussion of artificial intelligence in the third volume of this +series.) If you're interested, you should begin by reading Weizenbaum's +book, Computer Power and Human Reason, from which I quoted a passage +earlier. He argues not only that computers cannot do certain +things, but also that people should not use computers for certain +purposes even if it were possible. In particular, he is horrified at the +suggestion, made even by some psychiatrists, that programs like Eliza should +be used to provide therapy to actual patients. + +

Eliza's Linguistic Strategy

+ +

The program allows the user to enter one or more sentences, typing several +lines if necessary. The first step in processing the user's remarks is to +string the several lines into one long list. This list is a "sentence" in +the Logo technical sense; that is, it's a list of words with no sublist +structure. It may, however, contain one or more English sentences. The +generation of a response involves several steps: + +

+

  1. Find the punctuation in the input and use it to extract a single +sentence to answer. +
  2. Find keywords in the sentence for which the script includes rules. +
  3. Apply word-for-word translations as specified by the script; these +are primarily to convert first person ("I") to second person ("you") and +vice versa. +
  4. Pick the highest priority keyword. +
  5. Find a rule for that keyword whose pattern matches the input +sentence. +
  6. Choose a response according to that rule. +

+ +

These steps are not really quite sequential; for example, the +first two are done in parallel because, if there is more than one sentence, +the program chooses a sentence that contains one or more keywords. + +

I have omitted from this list several possible complications. One important +one is that there is a second kind of rule (besides the response rules) +called a memory rule. These rules do not generate immediate +responses to what the user types. Instead, they generate sentences that are +appropriate for later use, like "Earlier you said your spirits are low" in +the sample dialogue earlier. That response was not generated from the +user's comment just before it, but was instead added to memory at the time +of the user's first remark. Because the user's comment "Of course" +contained no keywords, the program chose to use a response from memory at +that time. + +

Other complications have to do with the nature of the rules associated with +a keyword. Instead of patterns and responses, a keyword can just have +another keyword as its rules, meaning that the rules for that keyword +should be used for this one also. Alternatively, another keyword can be +used in place of a response for a particular pattern, so the alternate +keyword is used only if that pattern is matched. Another alternative to +a response is the word "newkey," which means that the program should +abandon this keyword and try another one in the same sentence. Yet another +alternative is an instruction to rearrange the sentence and try matching +patterns again with the new version. As you read the procedures shown +below, try not to get caught up in these complications the first time +through. Just forget about the if instructions that check for these +special cases and concentrate on the usual situation. + +

I'll explain how each part of the linguistic strategy is carried out by +the procedures in the project. Here is a diagram of the +subprocedure/superprocedure relationships. The top-level doctor does +some initialization and then invokes loop, which does the real work. + +

figure: doctorflow
+ +

to doctor
+local [text sentence stuff a b c rules keywords memory]
+make "memory []
+print [Hello, I am the doctor. What can I do for you?]
+print [Please end your remarks with an empty line.]
+print []
+loop
+end
+
+to loop
+make "text tokenize getstuff []
+make "sentence getsentence :text
+analyze :sentence :keywords
+print []
+loop
+end
+
+ +

Loop uses getstuff to read several lines of the user's +typing into a long list. This list is processed by several procedures in +turn. + +

to getstuff :stuff
+localmake "line readlist
+if emptyp :line [output :stuff]
+output getstuff sentence :stuff :line
+end
+
+ +

The first step in my numbered list is to find the punctuation and use it to +extract a single sentence from the list. The first part, finding the +punctuation, is the job of tokenize and its subprocedure +tokenword. (These procedures get their name from the computer scientist's +term token, which means the smallest possible meaningful string of +characters. In the BASIC compiler of Chapter 6, the procedure called +reader separates a line of text into tokens.) + +

to tokenize :text
+output map.se [tokenword ? "] :text
+end
+
+to tokenword :word :out
+if emptyp :word [output :out]
+if memberp first :word [, " ] [output tokenword butfirst :word :out]
+if memberp first :word [. ? ! |;|] [output sentence :out ".]
+output tokenword butfirst :word word :out first :word
+end
+
+ +

The program's understanding of punctuation is +very simple. Some punctuation, like a quotation mark, is just ignored +completely. Periods, question marks, and semicolons are all treated as +having the same meaning, namely, they mark the end of a sentence. +tokenword turns a word like why? into the two-word list [why .] +so that the period as a separate word serves as the separator between +sentences in the long list. + +

Extracting a single sentence is done at the same time as steps 2 and 3, +finding keywords and applying translations. All of these are done by +getsentence, which uses checkpriority and translate as +subprocedures for tasks 2 and 3 respectively. (The version of Doctor +in the first edition worked with all capital letters. In this new version, +I've added a procedure decapitalize that turns the first letter of +each sentence to lower case, and when the program prints a +response it uses the inverse procedure capitalize to capitalize the +first word. This is necessary because the first word of the user's sentence +might end up in the middle of the program's response, and vice versa.) + +

to getsentence :text
+make "keywords []
+output getsentence1 decapitalize :text []
+end
+
+to getsentence1 :text :out
+if emptyp :text [output :out]
+if equalp first :text ". ~
+   [ifelse emptyp :keywords
+           [output getsentence1 decapitalize butfirst :text []]
+           [output :out]]
+checkpriority first :text
+output getsentence1 butfirst :text sentence :out translate first :text
+end
+
+to decapitalize :text
+if emptyp :text [output []]
+output fput lowercase first :text butfirst :text
+end
+
+to checkpriority :word
+localmake "priority gprop :word "priority
+if emptyp :priority [stop]
+if emptyp :keywords [make "keywords ( list :word ) stop]
+ifelse :priority > ( gprop first :keywords "priority ) ~
+       [make "keywords fput :word :keywords] ~
+       [make "keywords lput :word :keywords]
+end
+
+to translate :word
+localmake "new gprop :word "translation
+output ifelse emptyp :new [:word] [:new]
+end
+
+ +

At each sentence separator (a word containing only a period), +getsentence1 checks whether any keywords have been found yet. If so, the +sentence before the separator is the one the program uses. If not, +getsentence1 goes on to examine the next sentence in the list. If the last +sentence ends without any keywords found, that last sentence is chosen +anyway. + +

+ +

Both checkpriority and translate work through the use of +property lists that are associated with words. The script part of +doctor (Weizenbaum's second tier) consists of these property lists. +For example, here's part of the script setup: + +

pprop "my "priority 2
+pprop "my "translation "your
+
+ +

+ +

The first of these means that my is a keyword, with priority +2. In the Doctor script, most keywords have priority 0. My is a +little more important than most words, but not as important as dreamed +(priority 4) or computer (priority 50)! Checkpriority arranges +the list of keywords so that the word with highest priority is first in the +list. The translation property means that the word my is +changed to your in generating responses. For example, at the +beginning of the sample dialogue above, the sentence "My spirits are low" +is echoed as "Your spirits are low?" (The keyword list created by +checkpriority has untranslated keywords. That's why the +patterns associated with the keyword you, for example, all contain +the word I instead; the patterns deal with the translated version.) + +

Step 4, finding the highest priority keyword, is simply a matter of choosing +the first keyword in the list because of the way checkpriority +has done its job. This selection is made by analyze, which then +invokes checkrules as a subprocedure. (Analyze also recognizes +the special situation in which one keyword refers to the rules of another.) + +

to analyze :sentence :keywords
+local [rules keyword]
+if emptyp :keywords [norules stop]
+make "keyword first :keywords
+make "rules gprop :keyword "rules
+if wordp first :rules ~
+   [make "keyword first :rules make "rules gprop :keyword "rules]
+checkrules :keyword :rules
+end
+
+ +

Checkrules handles step 5, finding an applicable rule for the chosen +keyword. That is, checkrules invokes match to match the +selected sentence against each pattern associated with the given keyword. +(The program assumes that the script is written so that there will always be +at least one matching pattern. Most keywords have [#] as the pattern +in the last rule.) When checkrules finds a matching pattern, it +invokes dorule to examine the corresponding list of responses. (One +complication in understanding these procedures is that the input to +dorule is the name of a property whose value is the list of +responses. I'll get back to discussing why it's done this way later; for +now, all that's really important is that dorule chooses one of the +responses and uses it as the input to reconstruct.) + +

to checkrules :keyword :rules
+if not match first :rules :sentence ~
+   [checkrules :keyword butfirst butfirst :rules stop]
+dorule first butfirst :rules
+end
+
+to dorule :rule
+localmake "print first gprop :keyword :rule
+pprop :keyword :rule lput :print butfirst gprop :keyword :rule
+if equalp :print "newkey [analyze :sentence butfirst :keywords stop]
+if wordp :print [checkrules :print gprop :print "rules stop]
+if equalp first :print "pre ~
+   [analyze reconstruct first butfirst :print
+            butfirst butfirst :print
+    stop]
+print capitalize reconstruct :print
+memory :keyword :sentence
+end
+
+ +

The usual task of dorule is to carry out step 6, the generation of a +response. For example, when the user typed + +

My spirits are low.
+
+ +

the highest priority keyword found was my. There are three +patterns associated with this keyword: + +

[# your # !a:familyp #b]
+[# your &stuff]
+[#]
+
+ +

(Again, the pattern is matched against the sentence after +translation, so the patterns contain the word your even though the +actual keyword is my.) The first of these patterns does not match the +sentence. (Familyp is a predicate that's true for words like +mother and brother.) The second pattern, however, does match the +sentence. Match gives the variable stuff the list + +

[spirits are low]
+
+ +

as its value. (The period that ended what the user typed was +removed by tokenize.) + +

Associated with that second pattern is this list of responses: + +

[[Your :stuff?]
+ [Why do you say your :stuff?]
+ [Does that suggest anything else which belongs to you?]
+ [Is it important to you that your :stuff?]]
+
+ +

Dorule chooses the first of these, and invokes +reconstruct to substitute the actual value of the variable into the +response. By the way, although I've used Logo's notation of colon to mean +"the value of the variable," reconstruct isn't exactly like the Logo +interpreter. For one thing, it recognizes punctuation marks; it knows that +this response refers to a variable named stuff, not stuff?. + +

to reconstruct :sentence
+if emptyp :sentence [output []]
+if not equalp ": first first :sentence ~
+   [output fput first :sentence reconstruct butfirst :sentence]
+output sentence reword first :sentence reconstruct butfirst :sentence
+end
+
+to reword :word
+if memberp last :word [. ? ,] ~
+   [output addpunct reword butlast :word last :word]
+output thing butfirst :word
+end
+
+to addpunct :stuff :char
+if wordp :stuff [output word :stuff :char]
+if emptyp :stuff [output :char]
+output sentence butlast :stuff word last :stuff :char
+end
+
+ +

Stimulus-Response Psychology

+ +

Historically, there have been two ways of looking at the purpose of +artificial intelligence research. One way is to see it as research into +what computers can do, and into the meaning of intelligence in general, +without any special reference to how people think. Researchers who +take this approach are willing to use any technique that will solve a +problem, even if it's perfectly obvious that people don't think that way. +The second approach is to see artificial intelligence as a way to shed light +on human intelligence. In this approach, the idea is to use the computer as +a model for the human mind. Researchers who follow this path try to +write their programs to mimic human behavior and, they hope, even the inner +mechanisms of human brains. Recently there has been a tendency for +researchers to declare themselves as wholly in one camp or the other. +People who want to solve problems even if by non-human methods are part of +the "knowledge engineering" field; the programs they develop are called +"expert systems." People who want to use the computer to help build +theories of human intelligence are in the field of +"cognitive science." + +

Weizenbaum's work on Eliza is an early example of the former approach. He +was emphatically not claiming that his program worked the way people +work. Indeed, one of the purposes of the program was to demonstrate how +realistic the behavior of a computer program can be, even when we +are quite sure that the underlying mechanism is completely +unrealistic. + +

Nevertheless, Eliza could be taken as a computer model of a certain theory +of human psychology. It may not be obvious what it means for a computer +program to model a theory about people, so it may be worthwhile to examine +Eliza from this point of view. One theory about how people think is called +behaviorism, or the stimulus-response theory. +According to this theory, a person's mind is a "black box," and we can't +know what's inside. What we can know, however, is how a person +reacts to different situations and events. Whatever situation presents +itself to you is called a stimulus. A stimulus can be something very +abrupt like an electric shock, or it can be something more subtle like a +particular sentence spoken by a particular person. When you are presented +with a given stimulus, you produce a certain response: you say +something back, or you jump, or you fall asleep. People learn to associate +certain responses with certain stimuli. People can be trained to change the +response associated with a stimulus by using conditioning +techniques. If you are rewarded for producing a certain response, you'll +produce it more often. + +

The behaviorist theory was very influential several years ago, although +hardly anyone believes it any more. What would it mean to write a computer +model for this theory? Well, the model would have two main parts: one that +recognizes stimuli, and one that produces a response for a given stimulus. +In Eliza, the first part is the pattern matcher. I haven't spoken much +about that part of the program in this description because I discussed it at +length in the last project. But in fact match and its subprocedures +are a substantial part of the complete doctor program. The second +part, the one that produces responses, is dorule and reconstruct. + +

Eliza does not represent a very sophisticated form of stimulus-response +theory because it leaves out the idea of learning. In Eliza, the +responses are all provided in advance, as part of the script. People can +develop new responses over time, and behaviorist theory has a lot to say +about exactly what the rules are that govern such learning. (That's what +education is, to a behaviorist: learning new responses to stimuli.) Since +the script for Eliza is stored in lists, and those lists can be manipulated +by the program, it would be possible to modify the rules of the program so +that it can learn new rules while it's running. For example, if the user +types something like "What are you talking about?" then the program could +decide that its previous response was inappropriate. It would learn to +avoid that response next time. You might like to think about how to design +such an extension to the project as presented here. + +

Researchers who, unlike Weizenbaum, are deliberately trying to model +theories of human psychology generally use a more complicated program +structure. For example, experiments measuring the reaction time of human +beings in different situations seem to indicate that people have a +short-term memory and a long-term memory. The former may hold the telephone +number you're dialing right now, for instance, while the latter holds all +the telephone numbers of all your friends. Short-term memory is faster than +long-term, but much smaller; you can only remember a few things at a time in +it. Computers do not inherently have these two kinds of memory; they're +really good at remembering many things and finding them quickly. +But cognitive scientists write programs that deliberately limit the +computer's ability to remember things quickly, trying to model the inner +structure of the brain in this way. + +

Property Lists

+ +

The response rules, memory rules, translations, and priorities that make up +the script are all stored in the form of property lists. Each +keyword has a property list. For example, the property list for the word +my looks like this: + +

+ +

[priority 2
+ translation your
+ rules [[# your # !a:familyp #b] g1 [# your &stuff] g2 [#] g3]
+
+ g1 [[Tell me more about your family.]
+     [Who else in your family :b?]
+     [Your :a?]
+     [What else comes to mind when you think of your :a?]]
+ g2 [[Your :stuff?]
+     [Why do you say your :stuff?]
+     [Does that suggest anything else which belongs to you?]
+     [Is it important to you that your :stuff?]]
+ g3 [newkey]
+ memr [[# your &stuff] g4]
+ g4 [[Earlier you said your :stuff.]
+     [But your :stuff.]
+     [Does that have anything to do with your statement about :stuff?]]]
+
+ +

Remember that a property list contains pairs of members; the odd +numbered members are names of properties, and the even numbered members are +the values of those properties. The word my has properties named +priority, translation, rules, g1, g2, +g3, memr, and g4. The priority and translation +properties are straightforward. The rules and memr properties +have as their values lists in which the odd numbered members are patterns +and the even numbered members are names of other properties. These other +properties contain the lists of responses. The names of these secondary +properties are arbitrary and are generated by the program. + +

To create these property lists, I used pprop directly for some of the +properties, but wrote setup procedures to help with the more complicated +parts. Here are the instructions that contribute to this property list. + +

pprop "my "priority 2
+pprop "my "translation "your
+addrule "my [# your # !a:familyp #b]
+  [[Tell me more about your family.]
+   [Who else in your family :b?]
+   [Your :a?]
+   [What else comes to mind when you think of your :a?]]
+addrule "my [# your &stuff]
+  [[Your :stuff?]
+   [Why do you say your :stuff?]
+   [Does that suggest anything else which belongs to you?]
+   [Is it important to you that your :stuff?]]
+addrule "my [#] [newkey]
+addmemr "my [# your &stuff]
+  [[Earlier you said your :stuff.]
+   [But your :stuff.]
+   [Does that have anything to do with your statement about :stuff?]]
+
+ +

In general, the order in which properties are added to the list +doesn't matter. However, the order of the addrule instructions +does matter, because the rule that's added first is the one that +checkrules tries first. It's important, therefore, that the rules go +from most specific pattern to least specific pattern. In this case, the +first pattern checks for a remark about a member of the user's family; the +second checks for a remark about some other object or characteristic +belonging to the user; and the third is a catch-all pattern just in case the +other two fail. + +

+ +

Generated Symbols

+ + + + +

The procedures addrule and addmemr are very similar, since the +rules and memr properties are similar in format. + +

to addrule :word :pattern :results
+localmake "propname gensym
+pprop :word "rules (sentence gprop :word "rules list :pattern :propname)
+pprop :word :propname :results
+end
+
+to addmemr :word :pattern :results
+localmake "propname gensym
+pprop :word "memr (sentence gprop :word "memr list :pattern :propname)
+pprop :word :propname :results
+end
+
+ +

Each of these procedures uses a local variable propname to +contain the name of the response property, a "generated symbol" or +gensym. These are the words like g3 in the example above. Each +procedure carries out two pprop instructions. The first appends a new +pattern and a new gensym to the previous value of the rules or +memr property; the second creates a new property with the gensym as its +name and the response (or memory) list as its value. Gensym is +a Berkeley Logo library procedure. + +

Modification of List Structure

+ + + +

Why are generated symbols needed in this program at all? In the Lisp +version of Doctor, property lists are still used, but the entire collection +of rules is one big list, the value of the property rules. It's as if +the Logo property list looked like this: + +

+ +

[priority 2
+ translation your
+ rules
+   [[# your # !a:familyp #b]
+      [[Tell me more about your family.]
+       [Who else in your family :b?]
+       [Your :a?]
+       [What else comes to mind when you think of your :a?]]
+    [# your &stuff]
+      [[Your :stuff?]
+       [Why do you say your :stuff?]
+       [Does that suggest anything else which belongs to you?]
+       [Is it important to you that your :stuff?]]
+    [#]
+      [newkey]]
+ memr
+   [[# your &stuff]
+      [[Earlier you said your :stuff.]
+       [But your :stuff.]
+       [Does that have anything to do with your statement
+        about :stuff?]]]
+]
+
+ +

I chose not to use one big list of rules in the Logo version. In Lisp +(and in Berkeley Logo, but not in the versions of Logo I had available +when writing the first edition), it's possible to change +one of the members of a list without recopying the rest of the list. +Without that capability, it's better to divide the rules into separate, +smaller lists, so that only a little recopying is needed to change one. + +

Each pattern has several responses associated with it. When the program +matches a particular pattern, it does not choose a response at random. +Instead, it rotates through the list of responses in order. That is, it +uses the first response first, then the second, and so on until the end of +the list; if another response is needed, it starts over at the beginning of +the list. This strict rotation is sometimes important because some of the +responses say things like "I already told you that..." + +

The way the program keeps track of the rotation of the responses for a given +rule is that it actually changes the response list so that what used to be +the first response is moved to the end. Thus, dorule contains the +instructions + +

localmake "print first gprop :keyword :rule
+pprop :keyword :rule lput :print butfirst gprop :keyword :rule
+
+ +

The first of these instructions extracts the first response from +the list of responses. The second one replaces the list of responses with a +new list, in which the old first response is lput behind the remaining +ones. + +

+ +

What if the rules were one big list? To see what would be required, let's +look at a smaller list, in which it will be easier to follow what needs to +be changed. Suppose some word's rules property had as its value this +list: + +

[1 [A B C] 2 [D E F] 3 [G H I]]
+
+ +

In this example, the numbers represent patterns, while the letters +represent responses. Now suppose that the program finds a match for pattern +number 2. It should then issue the response D. Then it +should rotate the three responses associated with pattern 2 so that +the new rules property is + +

[1 [A B C] 2 [E F D] 3 [G H I]]
+
+ +

The only way to do this in most versions of Logo is to construct a +new copy of the entire list. Here is a way you could write such a program: + +

to rotate :keyword :pattern
+pprop :keyword "rules (rotate1 :pattern gprop :keyword "rules)
+end
+
+to rotate1 :pattern :rules
+if emptyp :rules [output []]
+if equalp :pattern first :rules
+   [output sentence (list :pattern rotate2 first butfirst :rules)
+                    (butfirst butfirst :rules)]
+output sentence (list first :rules first butfirst :rules) ~
+                (rotate1 :pattern butfirst butfirst :rules)
+end
+
+to rotate2 :list
+output lput first :list butfirst :list
+end
+
+ +

You'd use this program with an instruction like + +

rotate "word 2
+
+ +

where 2 represents the pattern in the example above. + +

The trouble with this approach is that it's slow. It does a lot of +list and sentence operations to reconstruct the modified list. +More importantly, the entire list must be copied, even though +only one rule is to be modified. + +

+In Lisp, and in Berkeley Logo, there are primitive commands that can be used +to change the contents of a list without recopying the unchanged parts. In +Berkeley Logo they are called .setfirst and .setbutfirst; using +them, we could write rotate this way: + +

to rotate :keyword :pattern
+rotate1 :pattern (gprop :keyword "rules)
+end
+
+to rotate1 :pattern :rules
+if emptyp :rules [stop]
+ifelse equalp :pattern first :rules ~
+       [.setfirst (butfirst :rules) (rotate2 first butfirst :rules)]
+       [rotate1 :pattern butfirst butfirst :rules]
+end
+
+ +

(I'll leave rotate2 the same as in the earlier version, for +now.) This is a tricky sort of procedure. Here's a trace of how it might +be used: + +

rotate "word 2
+  rotate1 2 [1 [A B C] 2 [D E F] 3 [G H I]]
+    rotate1 2 [2 [D E F] 3 [G H I]]
+
+ +

In the lower-level invocation of rotate1, the equalp +test outputs true, so the ifelse instruction evaluates its second +input. This is equivalent to the instruction + +

.setfirst [[D E F] 3 [G H I]] (rotate2 [D E F])
+
+ +

or + +

.setfirst [[D E F] 3 [G H I]] [E F D]
+
+ +

To understand what this means, you must realize that the primitive operation +butfirst does not make a copy of the butfirst of its input. +Instead, the list output by butfirst is actually part of the list that +is its input--they share the same cells in the computer's memory. +Therefore, to change something in the butfirst also changes the larger +list. The setfirst instruction ends up changing the rules +property of the word word even though there is no explicit +pprop to change the property. + +

If you're not a Lisp programmer, this probably seems like magic. It +certainly violates some of the rules you've learned about the evaluation of +Logo instructions. For example, if you actually typed the instruction + +

.setfirst [[D E F] 3 [G H I]] [E F D]
+
+ +

explicitly at top level, it would not change the property +list of word, because the list that setfirst modifies would +not be part of that property list, even though it has the same members. +It's only because setfirst's input is derived from that property list +by a series of butfirst operations that they share the same memory. + +

+ +

Do you find this confusing? The original designers of Logo chose not to include +.setfirst in the language because it is hard to understand, and +because it can produce some very strange results if you're not careful with +it. For example, consider these instructions: + +

make "c [x y]
+.setfirst (butfirst :c) (:c)
+
+ +

This .setfirst instruction will produce a +circular list, one that contains itself as a member. If you try +to print :c, you'll see something like + +

[x [x [x [x [x [x [x [x [x [x [x [x [x [x [x ...
+
+ +

going on forever. + +

Once we have these list modification tools, even the implicit recopying +done by lput can be avoided. Here's a more efficient version of +rotate1, but it's really tricky to understand and it isn't a +technique that I recommend: + +

+to rotate1 :pattern :rules
+if emptyp :rules [stop]
+ifelse equalp :pattern first :rules ~
+       [rotate2 butfirst :rules]
+       [rotate1 :pattern butfirst butfirst :rules]
+end
+
+to rotate2 :rulelist
+localmake "firstresponse first :rulelist
+localmake "restresponses butfirst :firstresponse
+.setfirst :rulelist :restresponses
+.setbutfirst :firstresponse []
+while [not emptyp butfirst :restresponses] ~
+      [make "restresponses butfirst :restresponses]
+.setbutfirst :restresponses :firstresponse
+end
+
+ +

In rotate2, the .setfirst instruction removes +the first response from the head of the list of responses; the two +.setbutfirst instructions "splice" that first response back +into the list at the end, following what used to be the last +response. + +

+Leaving .setfirst out of Logo was a controversial decision. Some +people take the position that, as a "language for learners," Logo should +not include mechanisms for which we can't provide an easy-to-follow +metaphor; it's counterproductive for the language to encourage you to think +in terms of what's where in memory. Other people refer to this idea +scornfully as "protecting the user from himself," arguing that if a +mechanism is useful it should be provided even though it's error-prone. + +

+ +

In any case, since Logo didn't have .setfirst and I didn't want the +doctor program to be slowed down by having to recopy the rules +property all the time, I decided to make each response list a separate +property, so that each response list can be modified independently of the +others. That's the reason for the gensym property names: so that +dorule can rotate the responses for a particular pattern without disturbing +the responses for other patterns. I could have changed this in the Berkeley +Logo version, but it didn't seem worthwhile; using names for the rules is a +little inelegant but doesn't hurt the program's efficiency. + +

Linguistic Structure

+ +

Because it treats a sentence as simply a string of words, Eliza is limited +in its linguistic sophistication. For example, the Doctor script has this +pattern associated with the keyword I: + +

[# you are # !stuff:in [sad unhappy depressed sick] #]
+
+ +

(Remember that the pattern is matched against the input sentence +after translation, so the words you are in the pattern really match a +sentence containing the words I am.) The purpose of the pattern is to +match a sentence like + +

I think I am really depressed because Susan doesn't like me.
+
+ +

The response of the program might be + +

I'm sorry to hear you are depressed.
+
+ +

The # between are and !stuff in the pattern is meant to +catch adverbs like the word really in the example I just gave. But it +could also "absorb" some more structurally important parts of a sentence: + +

I am sure that I would be depressed if she left me.
+
+ +

This sentence matches the pattern, but it doesn't really fit the +intent of the pattern. The person who types this sentence is not saying "I +am depressed" at all. + +

The trouble is that the string of words "sure that I would be" is not +equivalent to an adverb. In fact, these words do not form a phrase at all. +The program is making a grammatical error by connecting the word +depressed with the word am as a predicate adjective. To avoid such +errors, it's not good enough to have more and more detailed patterns to +match. You can't anticipate every possible string of words by that +technique. Instead, the program would have to impose a tree structure on +the sentence, sort of like what you did in diagraming sentences in +elementary school. The true structure of this sentence is something like + +

[[subject I] [predicate [[verb am] [nominative [[adjective sure]
+   [adverb [clause [[connective that] [subject I] [verb [would be] ...
+
+ +

and so on. (Actually, I've just made up this structure to +illustrate the idea, and it's not very realistic. I've tried too hard to +preserve the order of the words in the original sentence. A more practical +structure would probably center on the verb in each clause, and have +subordinate slots for the subject, object, and so on. A connective like +"that" might just be thrown away completely; the purpose served by such +words in spoken text would instead be filled by the very sublist +organization itself.) People have in fact written several computer programs +that transform English sentences into a structured representation. It's very +hard to do a perfect job, though, because of problems like homonyms: the +word "like" can be a verb (I like ice cream) or a preposition (I want to +be like my big brother). + +

Further Explorations

+ +

There are three main directions in which you can explore the territory that +this project begins. First, you can try to refine the existing Doctor +script, so that it does a better job within the same general framework. +Whenever you get an inappropriate response from doctor, see if you can +think of a new rule that would solve that case without messing up other +sentences. + +

A second possibility would be to write an entirely new Eliza script, so that +instead of being a doctor the program can carry on some different sort of +conversation. How about taking orders in a fast food restaurant? Answering +questions from some data base about presidents or baseball players? + +

The third direction would be to abandon Eliza and look into some of the +other approaches to understanding and generating English sentences that have +been developed. + +

+
(back to Table of Contents) +BACK +chapter thread NEXT +
+ +

Program Listing

+ +

The procedures from the pattern matcher of Chapter 7 are included in +this program, but they are not listed again here. + +

+to doctor
+local [text sentence stuff a b c rules keywords memory]
+make "memory []
+print [Hello, I am the doctor. What can I do for you?]
+print [Please end your remarks with an empty line.]
+print []
+loop
+end
+
+;; Controlling the conversation
+
+to loop
+make "text tokenize getstuff []
+make "sentence getsentence :text
+analyze :sentence :keywords
+print []
+loop
+end
+
+;; Reading and preparing the input
+
+to getstuff :stuff
+localmake "line readlist
+if emptyp :line [output :stuff]
+output getstuff sentence :stuff :line
+end
+
+to tokenize :text
+output map.se [tokenword ? "] :text
+end
+
+to tokenword :word :out
+if emptyp :word [output :out]
+if memberp first :word [, " ] [output tokenword butfirst :word :out]
+if memberp first :word [. ? ! |;|] [output sentence :out ".]
+output tokenword butfirst :word word :out first :word
+end
+
+to getsentence :text
+make "keywords []
+output getsentence1 decapitalize :text []
+end
+
+to getsentence1 :text :out
+if emptyp :text [output :out]
+if equalp first :text ". ~
+   [ifelse emptyp :keywords ~
+           [output getsentence1 decapitalize butfirst :text []] [output :out]]
+checkpriority first :text
+output getsentence1 butfirst :text sentence :out translate first :text
+end
+
+to decapitalize :text
+if emptyp :text [output []]
+output fput lowercase first :text butfirst :text
+end
+
+to checkpriority :word
+localmake "priority gprop :word "priority
+if emptyp :priority [stop]
+if emptyp :keywords [make "keywords ( list :word ) stop]
+ifelse :priority > ( gprop first :keywords "priority ) ~
+       [make "keywords fput :word :keywords] ~
+       [make "keywords lput :word :keywords]
+end
+
+to translate :word
+localmake "new gprop :word "translation
+output ifelse emptyp :new [:word] [:new]
+end
+
+;; Choosing the rule and replying
+
+to analyze :sentence :keywords
+local [rules keyword]
+if emptyp :keywords [norules stop]
+make "keyword first :keywords
+make "rules gprop :keyword "rules
+if wordp first :rules ~
+   [make "keyword first :rules make "rules gprop :keyword "rules]
+checkrules :keyword :rules
+end
+
+to checkrules :keyword :rules
+if not match first :rules :sentence ~
+   [checkrules :keyword butfirst butfirst :rules stop]
+dorule first butfirst :rules
+end
+
+to dorule :rule
+localmake "print first gprop :keyword :rule
+pprop :keyword :rule lput :print butfirst gprop :keyword :rule
+if equalp :print "newkey [analyze :sentence butfirst :keywords stop]
+if wordp :print [checkrules :print gprop :print "rules stop]
+if equalp first :print "pre ~
+   [analyze reconstruct first butfirst :print butfirst butfirst :print stop]
+print capitalize reconstruct :print
+memory :keyword :sentence
+end
+
+to reconstruct :sentence
+if emptyp :sentence [output []]
+if not equalp ": first first :sentence ~
+   [output fput first :sentence reconstruct butfirst :sentence]
+output sentence reword first :sentence reconstruct butfirst :sentence
+end
+
+to reword :word
+if memberp last :word [. ? ,] [output addpunct reword butlast :word last :word]
+output thing butfirst :word
+end
+
+to addpunct :stuff :char
+if wordp :stuff [output word :stuff :char]
+if emptyp :stuff [output :char]
+output sentence butlast :stuff word last :stuff :char
+end
+
+to capitalize :text
+if emptyp :text [output []]
+output fput (word uppercase first first :text butfirst first :text) butfirst :text
+end
+
+to memory :keyword :sentence
+local [rules rule name]
+make "rules gprop :keyword "memr
+if emptyp :rules [stop]
+if not match first :rules :sentence [stop]
+make "name last :rules
+make "rules gprop :keyword :name
+make "rule first :rules
+pprop :keyword :name lput :rule butfirst :rules
+make "memory fput reconstruct :sentence :memory
+end
+
+to norules
+ifelse :memflag [usememory] [lastresort]
+make "memflag not :memflag
+end
+
+to lastresort
+print first :lastresort
+make "lastresort lput first :lastresort butfirst :lastresort
+end
+
+to usememory
+if emptyp :memory [lastresort stop]
+print capitalize first :memory
+make "memory butfirst :memory
+end
+
+;; Predicates for patterns
+
+to beliefp :word
+output not emptyp gprop :word "belief
+end
+
+to familyp :word
+output not emptyp gprop :word "family
+end
+
+;; Procedures for adding to the script
+
+to addrule :word :pattern :results
+localmake "propname gensym
+pprop :word "rules (sentence gprop :word "rules list :pattern :propname)
+pprop :word :propname :results
+end
+
+to addmemr :word :pattern :results
+localmake "propname gensym
+pprop :word "memr (sentence gprop :word "memr list :pattern :propname)
+pprop :word :propname :results
+end
+
+;; data
+
+make "gensym.number 80
+
+make "lastresort [[I am not sure I understand you fully.] [Please go on.]
+                  [What does that suggest to you?]
+                  [Do you feel strongly about discussing such things?]]
+
+make "memflag "false
+
+pprop "alike "priority 10
+pprop "alike "rules [dit]
+
+pprop "always "priority 1
+pprop "always "rules [[#] g69]
+pprop "always "g69 [[Can you think of a specific example?] [When?]
+                    [What incident are you thinking of?]
+                    [Really, always?] [What if this never happened?]]
+
+pprop "am "priority 0
+pprop "am "translation "are
+pprop "am "rules [[# are you #stuff] g18 [#] g19]
+pprop "am "g18 [[Do you believe you are :stuff?] [Would you want to be :stuff?]
+                [You wish I would tell you you are :stuff.]
+                [What would it mean if you were :stuff?] how]
+pprop "am "g19 [[Why do you say "am"?] [I don't understand that.]]
+
+pprop "are "priority 0
+pprop "are "rules [[#a there are #b you #c] g20 [# there are &stuff] g21
+                   [# are I #stuff] g22 [are #] g23 [# are #stuff] g24]
+pprop "are "g20 [[pre [:a there are :b] are]]
+pprop "are "g21 [[What makes you think there are :stuff?]
+                 [Do you usually consider :stuff?]
+                 [Do you wish there were :stuff?]]
+pprop "are "g22 [[Why are you interested in whether I am :stuff or not?]
+                 [Would you prefer if I weren't :stuff?]
+                 [Perhaps I am :stuff in your fantasies.]
+                 [Do you sometimes think I am :stuff?] how]
+pprop "are "g23 [how]
+pprop "are "g24 [[Did you think they might not be :stuff?]
+                 [Would you like it if they were not :stuff?]
+                 [What if they were not :stuff?] [Possibly they are :stuff.]]
+
+pprop "ask "priority 0
+pprop "ask "rules [[# you ask #] g77 [# you ! asking #] g78 [# I #] g79 [#] g80]
+pprop "ask "g77 [how]
+pprop "ask "g78 [how]
+pprop "ask "g79 [you]
+pprop "ask "g80 [newkey]
+
+pprop "because "priority 0
+pprop "because "rules [[#] g64]
+pprop "because "g64 [[Is that the real reason?]
+                     [Don't any other reasons come to mind?]
+                     [Does that reason seem to explain anything else?]
+                     [What other reasons might there be?]
+                     [You're not concealing anything from me, are you?]]
+
+pprop "believe "belief "true
+
+pprop "bet "belief "true
+
+pprop "brother "family "true
+
+pprop "can "priority 0
+pprop "can "rules [[# can I #stuff] g58 [# can you #stuff] g59 [#] g60]
+pprop "can "g58 [[You believe I can :stuff, don't you?] how
+                 [You want me to be able to :stuff.]
+                 [Perhaps you would like to be able to :stuff yourself.]]
+pprop "can "g59 [[Whether or not you can :stuff depends more on you than on me.]
+                 [Do you want to be able to :stuff?]
+                 [Perhaps you don't want to :stuff.] how]
+pprop "can "g60 [how newkey]
+
+pprop "cant "translation "can't
+
+pprop "certainly "priority 0
+pprop "certainly "rules [yes]
+
+pprop "children "family "true
+
+pprop "computer "priority 50
+pprop "computer "rules [[#] g17]
+pprop "computer "g17 [[Do computers worry you?]
+                      [Why do you mention computers?]
+                      [What do you think machines have to do with your problem?]
+                      [Don't you think computers can help people?]
+                      [What about machines worries you?]
+                      [What do you think about machines?]]
+
+pprop "computers "priority 50
+pprop "computers "rules [computer]
+
+pprop "dad "translation "father
+pprop "dad "family "true
+
+pprop "daddy "translation "father
+pprop "daddy "family "true
+
+pprop "deutsch "priority 0
+pprop "deutsch "rules [[#] g15]
+pprop "deutsch "g15 [[I'm sorry, I speak only English.]]
+
+pprop "dit "rules [[#] g72]
+pprop "dit "g72 [[In what way?] [What resemblance do you see?]
+                 [What does that similarity suggest to you?]
+                 [What other connections do you see?]
+                 [What do you suppose that resemblance means?]
+                 [What is the connection, do you suppose?]
+                 [Could there really be some connection?] how]
+
+pprop "dont "translation "don't
+
+pprop "dream "priority 3
+pprop "dream "rules [[#] g9]
+pprop "dream "g9 [[What does that dream suggest to you?] [Do you dream often?]
+                  [What persons appear in your dreams?]
+                  [Don't you believe that dream has something to do
+                   with your problem?]
+                  [Do you ever wish you could flee from reality?] newkey]
+
+pprop "dreamed "priority 4
+pprop "dreamed "rules [[# you dreamed #stuff] g7 [#] g8]
+pprop "dreamed "g7 [[Really :stuff?]
+                    [Have you ever fantasied :stuff while you were awake?]
+                    [Have you dreamed :stuff before?] dream newkey]
+pprop "dreamed "g8 [dream newkey]
+
+pprop "dreams "translation "dream
+pprop "dreams "priority 3
+pprop "dreams "rules [dream]
+
+pprop "dreamt "translation "dreamed
+pprop "dreamt "priority 4
+pprop "dreamt "rules [dreamed]
+
+pprop "espanol "priority 0
+pprop "espanol "rules [deutsch]
+
+pprop "everybody "priority 2
+pprop "everybody "rules [everyone]
+
+pprop "everyone "priority 2
+pprop "everyone "rules [[# !a:in [everyone everybody nobody noone] #] g68]
+pprop "everyone "g68 [[Really, :a?] [Surely not :a.]
+                      [Can you think of anyone in particular?]
+                      [Who, for example?]
+                      [You are thinking of a very special person.]
+                      [Who, may I ask?] [Someone special perhaps.]
+                      [You have a particular person in mind, don't you?]
+                      [Who do you think you're talking about?]
+                      [I suspect you're exaggerating a little.]]
+
+pprop "father "family "true
+
+pprop "feel "belief "true
+
+pprop "francais "priority 0
+pprop "francais "rules [deutsch]
+
+pprop "hello "priority 0
+pprop "hello "rules [[#] g16]
+pprop "hello "g16 [[How do you do. Please state your problem.]]
+
+pprop "how "priority 0
+pprop "how "rules [[#] g63]
+pprop "how "g63 [[Why do you ask?] [Does that question interest you?]
+                 [What is it you really want to know?]
+                 [Are such questions much on your mind?]
+                 [What answer would please you most?] [What do you think?]
+                 [What comes to your mind when you ask that?]
+                 [Have you asked such questions before?]
+                 [Have you asked anyone else?]]
+
+pprop "husband "family "true
+
+pprop "i "priority 0
+pprop "i "translation "you
+pprop "i "rules [[# you !:in [want need] #stuff] g32
+                 [# you are # !stuff:in [sad unhappy depressed sick] #] g33
+                 [# you are # !stuff:in [happy elated glad better] #] g34
+                 [# you was #] g35 [# you !:beliefp you #stuff] g36
+                 [# you # !:beliefp # i #] g37 [# you are #stuff] g38
+                 [# you !:in [can't cannot] #stuff] g39
+                 [# you don't #stuff] g40 [# you feel #stuff] g41
+                 [# you #stuff i #] g42 [#stuff] g43]
+pprop "i "g32 [[What would it mean to you if you got :stuff?]
+               [Why Do you want :stuff?] [Suppose you got :stuff soon.]
+               [What if you never got :stuff?]
+               [What would getting :stuff mean to you?] [You really want :stuff.]
+               [I suspect you really don't want :stuff.]]
+pprop "i "g33 [[I'm sorry to hear you are :stuff.]
+               [Do you think coming here will help you not to be :stuff?]
+               [I'm sure it's not pleasant to be :stuff.]
+               [Can you explain what made you :stuff?] [Please go on.]]
+pprop "i "g34 [[How have I helped you to be :stuff?]
+               [Has your treatment made you :stuff?]
+               [What makes you :stuff just now?]
+               [Can you explain why you are suddenly :stuff?]
+               [Are you sure?] [What do you mean by :stuff?]]
+pprop "i "g35 [was]
+pprop "i "g36 [[Do you really think so?] [But you are not sure you :stuff.]
+               [Do you really doubt you :stuff?]]
+pprop "i "g37 [you]
+pprop "i "g38 [[Is it because you are :stuff that you came to me?]
+               [How long have you been :stuff?]
+               [Do you believe it normal to be :stuff?]
+               [Do you enjoy being :stuff?]]
+pprop "i "g39 [[How do you know you can't :stuff?] [Have you tried?]
+               [Perhaps you could :stuff now.]
+               [Do you really want to be able to :stuff?]]
+pprop "i "g40 [[Don't you really :stuff?] [Why don't you :stuff?]
+               [Do you wish to be able to :stuff?] [Does that trouble you?]]
+
+pprop "i "g41 [[Tell me more about such feelings.] [Do you often feel :stuff?]
+               [Do you enjoy feeling :stuff?]
+               [Of what does feeling :stuff remind you?]]
+pprop "i "g42 [[Perhaps in your fantasy we :stuff each other.]
+               [Do you wish to :stuff me?] [You seem to need to :stuff me.]
+               [Do you :stuff anyone else?]]
+pprop "i "g43 [[You say :stuff.] [Can you elaborate on that?]
+               [Do you say :stuff for some special reason?]
+               [That's quite interesting.]]
+
+pprop "i'm "priority 0
+pprop "i'm "translation "you're
+pprop "i'm "rules [[# you're #stuff] g31]
+pprop "i'm "g31 [[pre [you are :stuff] I]]
+
+pprop "if "priority 3
+pprop "if "rules [[#a if #b had #c] g5 [# if #stuff] g6]
+pprop "if "g5 [[pre [:a if :b might have :c] if]]
+pprop "if "g6 [[Do you think it's likely that :stuff?] [Do you wish that :stuff?]
+               [What do you think about :stuff?]]
+
+pprop "is "priority 0
+pprop "is "rules [[&a is &b] g61 [#] g62]
+pprop "is "g61 [[Suppose :a were not :b.] [Perhaps :a really is :b.]
+                [Tell me more about :a.]]
+pprop "is "g62 [newkey]
+
+pprop "italiano "priority 0
+pprop "italiano "rules [deutsch]
+
+pprop "like "priority 10
+pprop "like "rules [[# !:in [am is are was] # like #] g70 [#] g71]
+pprop "like "g70 [dit]
+pprop "like "g71 [newkey]
+
+pprop "machine "priority 50
+pprop "machine "rules [computer]
+
+pprop "machines "priority 50
+pprop "machines "rules [computer]
+
+pprop "maybe "priority 0
+pprop "maybe "rules [perhaps]
+
+pprop "me "translation "you
+
+pprop "mom "translation "mother
+pprop "mom "family "true
+
+pprop "mommy "translation "mother
+pprop "mommy "family "true
+
+pprop "mother "family "true
+
+pprop "my "priority 2
+pprop "my "translation "your
+pprop "my "rules [[# your # !a:familyp #b] g55 [# your &stuff] g56 [#] g57]
+pprop "my "g55 [[Tell me more about your family.] [Who else in your family :b?]
+                [Your :a?] [What else comes to mind when you think of your :a?]]
+pprop "my "g56 [[Your :stuff?] [Why do you say your :stuff?]
+                [Does that suggest anything else which belongs to you?]
+                [Is it important to you that your :stuff?]]
+pprop "my "g57 [newkey]
+pprop "my "memr [[# your &stuff] g12]
+pprop "my "g12 [[Earlier you said your :stuff.] [But your :stuff.]
+                [Does that have anything to do with your statement about :stuff?]]
+
+pprop "myself "translation "yourself
+
+pprop "name "priority 15
+pprop "name "rules [[#] g14]
+pprop "name "g14 [[I am not interested in names.]
+                  [I've told you before I don't care about names\;
+                   please continue.]]
+
+pprop "no "priority 0
+pprop "no "rules [[no] g53 [#] g54]
+pprop "no "g53 [xxyyzz [pre [x no] no]]
+pprop "no "g54 [[Are you saying "no" just to be negative?]
+                [You are being a bit negative.] [Why not?] [Why "no"?] newkey]
+
+pprop "nobody "priority 2
+pprop "nobody "rules [everyone]
+
+pprop "noone "priority 2
+pprop "noone "rules [everyone]
+
+pprop "perhaps "priority 0
+pprop "perhaps "rules [[#] g13]
+pprop "perhaps "g13 [[You don't seem quite certain.] [Why the uncertain tone?]
+                     [Can't you be more positive?] [You aren't sure.]
+                     [Don't you know?]]
+
+pprop "problem "priority 5
+pprop "problem "rules [[#a !b:in [is are] your !c:in [problem problems] #] g73
+                       [# your !a:in [problem problems] !b:in [is are] #c] g74
+                       [#] g75]
+pprop "problem "g73 [[:a :b your :c.] [Are you sure :a :b your :c?]
+                     [Perhaps :a :b not your real :c.]
+                     [You think you have problems?]
+                     [Do you often think about :a?]]
+pprop "problem "g74 [[Your :a :b :c?] [Are you sure your :a :b :c?]
+                     [Perhaps your real :a :b not :c.]
+                     [You think you have problems?]]
+pprop "problem "g75 [[Please continue, this may be interesting.]
+                     [Have you any other problems you wish to discuss?]
+                     [Perhaps you'd rather change the subject.]
+                     [You seem a bit uneasy.] newkey]
+pprop "problem "memr [[#stuff is your problem #] g76]
+pprop "problem "g76 [[Earlier you mentioned :stuff.]
+                     [Let's talk further about :stuff.]
+                     [Tell me more about :stuff.]
+                     [You haven't mentioned :stuff for a while.]]
+
+pprop "problems "priority 5
+pprop "problems "rules [problem]
+
+pprop "remember "priority 5
+pprop "remember "rules [[# you remember #stuff] g2
+                        [# do I remember #stuff] g3 [#] g4]
+pprop "remember "g2 [[Do you often think of :stuff?]
+                     [Does thinking of :stuff bring anything else to mind?]
+                     [What else do you remember?]
+                     [Why do you remember :stuff just now?]
+                     [What in the present situation reminds you of :stuff?]]
+pprop "remember "g3 [[Did you think I would forget :stuff?]
+                     [Why do you think I should recall :stuff now?]
+                     [What about :stuff?] what [You mentioned :stuff.]]
+pprop "remember "g4 [newkey]
+
+pprop "same "priority 10
+pprop "same "rules [dit]
+
+pprop "sister "family "true
+
+pprop "sorry "priority 0
+pprop "sorry "rules [[#] g1]
+pprop "sorry "g1 [[Please don't apologize.] [Apologies are not necessary.]
+                  [What feelings do you have when you apologize?]
+                  [I've told you that apologies are not required.]]
+
+pprop "svenska "priority 0
+pprop "svenska "rules [deutsch]
+
+pprop "think "belief "true
+
+pprop "was "priority 2
+pprop "was "rules [[# was you #stuff] g26 [# you was #stuff] g27
+                   [# was I #stuff] g28 [#] g29]
+pprop "was "g26 [[What if you were :stuff?] [Do you think you were :stuff?]
+                 [Were you :stuff?] [What would it mean if you were :stuff?]
+                 [What does " :stuff " suggest to you?] how]
+pprop "was "g27 [[Were you really?] [Why do you tell me you were :stuff now?]
+                 [Perhaps I already knew you were :stuff.]]
+pprop "was "g28 [[Would you like to believe I was :stuff?]
+                 [What suggests that I was :stuff?] [What do you think?]
+                 [Perhaps I was :stuff.] [What if I had been :stuff?]]
+pprop "was "g29 [newkey]
+
+pprop "we "translation "you
+pprop "we "priority 0
+pprop "we "rules [I]
+
+pprop "were "priority 0
+pprop "were "translation "was
+pprop "were "rules [was]
+
+pprop "what "priority 0
+pprop "what "rules [[!:in [what where] #] g10 [# !a:in [what where] #b] g11]
+pprop "what "g10 [how]
+pprop "what "g11 [[Tell me about :a :b.] [:a :b?]
+                  [Do you want me to tell you :a :b?]
+                  [Really.] [I see.] newkey]
+
+pprop "where "priority 0
+pprop "where "rules [how]
+
+pprop "why "priority 0
+pprop "why "rules [[# why don't I #stuff] g65
+                   [# why can't you #stuff] g66 [#] g67]
+pprop "why "g65 [[Do you believe I don't :stuff?]
+                 [Perhaps I will :stuff in good time.]
+                 [Should you :stuff yourself?] [You want me to :stuff?] how]
+pprop "why "g66 [[Do you think you should be able to :stuff?]
+                 [Do you want to be able to :stuff?]
+                 [Do you believe this will help you to :stuff?]
+                 [Have you any idea why you can't :stuff?] how]
+pprop "why "g67 [[Why indeed?] [Why "why"?] [Why not?] how newkey]
+
+pprop "wife "family "true
+
+pprop "wish "belief "true
+
+pprop "wont "translation "won't
+
+pprop "xxyyzz "priority 0
+pprop "xxyyzz "rules [[#] g50]
+pprop "xxyyzz "g50 [[You're being somewhat short with me.]
+                    [You don't seem very talkative today.]
+                    [Perhaps you'd rather talk about something else.]
+                    [Are you using monosyllables for some reason?] newkey]
+
+pprop "yes "priority 0
+pprop "yes "rules [[yes] g51 [#] g52]
+pprop "yes "g51 [xxyyzz [pre [x yes] yes]]
+pprop "yes "g52 [[You seem quite positive.] [You are sure.] [I see.]
+                 [I understand.] newkey]
+
+pprop "you "priority 0
+pprop "you "translation "I
+pprop "you "rules [[# I remind you of #] g44 [# I are # you #] g45
+                   [# I # are #stuff] g46 [# I #stuff you] g47
+                   [# I &stuff] g48 [#] g49]
+pprop "you "g44 [dit]
+pprop "you "g45 [newkey]
+pprop "you "g46 [[What makes you think I am :stuff?]
+                 [Does it please you to believe I am :stuff?]
+                 [Perhaps you would like to be :stuff.]
+                 [Do you sometimes wish you were :stuff?]]
+pprop "you "g47 [[Why do you think I :stuff you?]
+                 [You like to think I :stuff you, don't you?]
+                 [What makes you think I :stuff you?] [Really, I :stuff you?]
+                 [Do you wish to believe I :stuff you?]
+                 [Suppose I did :stuff you. what would that mean?]
+                 [Does someone else believe I :stuff you?]]
+pprop "you "g48 [[We were discussing you, not me.] [Oh, I :stuff?]
+                 [Is this really relevant to your problem?] [Perhaps I do :stuff.]
+                 [Are you glad to know I :stuff?] [Do you :stuff?]
+                 [What are your feelings now?]]
+pprop "you "g49 [newkey]
+
+pprop "you're "priority 0
+pprop "you're "translation "I'm
+pprop "you're "rules [[# I'm #stuff] g30]
+pprop "you're "g30 [[pre [I are :stuff] you]]
+
+pprop "your "priority 0
+pprop "your "translation "my
+pprop "your "rules [[# my #stuff] g25]
+pprop "your "g25 [[Why are you concerned over my :stuff?]
+                  [What about your own :stuff?]
+                  [Are you worried about someone else's :stuff?]
+                  [Really, my :stuff?]]
+
+pprop "yourself "translation "myself
+
+ +

(back to Table of Contents) +

BACK +chapter thread NEXT + +

+

+Brian Harvey, +bh@cs.berkeley.edu +
+ + diff --git a/js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif b/js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif new file mode 100644 index 0000000..c904f65 Binary files /dev/null and b/js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif differ diff --git a/js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg b/js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg new file mode 100644 index 0000000..b280556 --- /dev/null +++ b/js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg @@ -0,0 +1,794 @@ +to doctor +local [text sentence stuff a b c rules keywords memory] +make "memory [] +print [Hello, I am the doctor. What can I do for you?] +print [Please end your remarks with an empty line.] +print [] +loop +end + +;; Controlling the conversation + +to loop +make "text tokenize getstuff [] +make "sentence getsentence :text +analyze :sentence :keywords +print [] +loop +end + +;; Reading and preparing the input + +to getstuff :stuff +localmake "line readlist +if emptyp :line [output :stuff] +output getstuff sentence :stuff :line +end + +to tokenize :text +output map.se [tokenword ? "] :text +end + +to tokenword :word :out +if emptyp :word [output :out] +if memberp first :word [, " ] [output tokenword butfirst :word :out] +if memberp first :word [. ? ! |;|] [output sentence :out ".] +output tokenword butfirst :word word :out first :word +end + +to getsentence :text +make "keywords [] +output getsentence1 decapitalize :text [] +end + +to getsentence1 :text :out +if emptyp :text [output :out] +if equalp first :text ". ~ + [ifelse emptyp :keywords ~ + [output getsentence1 decapitalize butfirst :text []] [output :out]] +checkpriority first :text +output getsentence1 butfirst :text sentence :out translate first :text +end + +to decapitalize :text +if emptyp :text [output []] +output fput lowercase first :text butfirst :text +end + +to checkpriority :word +localmake "priority gprop :word "priority +if emptyp :priority [stop] +if emptyp :keywords [make "keywords ( list :word ) stop] +ifelse :priority > ( gprop first :keywords "priority ) ~ + [make "keywords fput :word :keywords] ~ + [make "keywords lput :word :keywords] +end + +to translate :word +localmake "new gprop :word "translation +output ifelse emptyp :new [:word] [:new] +end + +;; Choosing the rule and replying + +to analyze :sentence :keywords +local [rules keyword] +if emptyp :keywords [norules stop] +make "keyword first :keywords +make "rules gprop :keyword "rules +if wordp first :rules ~ + [make "keyword first :rules make "rules gprop :keyword "rules] +checkrules :keyword :rules +end + +to checkrules :keyword :rules +if not match first :rules :sentence ~ + [checkrules :keyword butfirst butfirst :rules stop] +dorule first butfirst :rules +end + +to dorule :rule +localmake "print first gprop :keyword :rule +pprop :keyword :rule lput :print butfirst gprop :keyword :rule +if equalp :print "newkey [analyze :sentence butfirst :keywords stop] +if wordp :print [checkrules :print gprop :print "rules stop] +if equalp first :print "pre ~ + [analyze reconstruct first butfirst :print butfirst butfirst :print stop] +print capitalize reconstruct :print +memory :keyword :sentence +end + +to reconstruct :sentence +if emptyp :sentence [output []] +if not equalp ": first first :sentence ~ + [output fput first :sentence reconstruct butfirst :sentence] +output sentence reword first :sentence reconstruct butfirst :sentence +end + +to reword :word +if memberp last :word [. ? ,] [output addpunct reword butlast :word last :word] +output thing butfirst :word +end + +to addpunct :stuff :char +if wordp :stuff [output word :stuff :char] +if emptyp :stuff [output :char] +output sentence butlast :stuff word last :stuff :char +end + +to capitalize :text +if emptyp :text [output []] +output fput (word uppercase first first :text butfirst first :text) butfirst :text +end + +to memory :keyword :sentence +local [rules rule name] +make "rules gprop :keyword "memr +if emptyp :rules [stop] +if not match first :rules :sentence [stop] +make "name last :rules +make "rules gprop :keyword :name +make "rule first :rules +pprop :keyword :name lput :rule butfirst :rules +make "memory fput reconstruct :sentence :memory +end + +to norules +ifelse :memflag [usememory] [lastresort] +make "memflag not :memflag +end + +to lastresort +print first :lastresort +make "lastresort lput first :lastresort butfirst :lastresort +end + +to usememory +if emptyp :memory [lastresort stop] +print capitalize first :memory +make "memory butfirst :memory +end + +;; Predicates for patterns + +to beliefp :word +output not emptyp gprop :word "belief +end + +to familyp :word +output not emptyp gprop :word "family +end + +;; Procedures for adding to the script + +to addrule :word :pattern :results +localmake "propname gensym +pprop :word "rules (sentence gprop :word "rules list :pattern :propname) +pprop :word :propname :results +end + +to addmemr :word :pattern :results +localmake "propname gensym +pprop :word "memr (sentence gprop :word "memr list :pattern :propname) +pprop :word :propname :results +end + +;; data + +make "gensym.number 80 + +make "lastresort [[I am not sure I understand you fully.] [Please go on.] + [What does that suggest to you?] + [Do you feel strongly about discussing such things?]] + +make "memflag "false + +pprop "alike "priority 10 +pprop "alike "rules [dit] + +pprop "always "priority 1 +pprop "always "rules [[#] g69] +pprop "always "g69 [[Can you think of a specific example?] [When?] + [What incident are you thinking of?] + [Really, always?] [What if this never happened?]] + +pprop "am "priority 0 +pprop "am "translation "are +pprop "am "rules [[# are you #stuff] g18 [#] g19] +pprop "am "g18 [[Do you believe you are :stuff?] [Would you want to be :stuff?] + [You wish I would tell you you are :stuff.] + [What would it mean if you were :stuff?] how] +pprop "am "g19 [[Why do you say "am"?] [I don't understand that.]] + +pprop "are "priority 0 +pprop "are "rules [[#a there are #b you #c] g20 [# there are &stuff] g21 + [# are I #stuff] g22 [are #] g23 [# are #stuff] g24] +pprop "are "g20 [[pre [:a there are :b] are]] +pprop "are "g21 [[What makes you think there are :stuff?] + [Do you usually consider :stuff?] + [Do you wish there were :stuff?]] +pprop "are "g22 [[Why are you interested in whether I am :stuff or not?] + [Would you prefer if I weren't :stuff?] + [Perhaps I am :stuff in your fantasies.] + [Do you sometimes think I am :stuff?] how] +pprop "are "g23 [how] +pprop "are "g24 [[Did you think they might not be :stuff?] + [Would you like it if they were not :stuff?] + [What if they were not :stuff?] [Possibly they are :stuff.]] + +pprop "ask "priority 0 +pprop "ask "rules [[# you ask #] g77 [# you ! asking #] g78 [# I #] g79 [#] g80] +pprop "ask "g77 [how] +pprop "ask "g78 [how] +pprop "ask "g79 [you] +pprop "ask "g80 [newkey] + +pprop "because "priority 0 +pprop "because "rules [[#] g64] +pprop "because "g64 [[Is that the real reason?] + [Don't any other reasons come to mind?] + [Does that reason seem to explain anything else?] + [What other reasons might there be?] + [You're not concealing anything from me, are you?]] + +pprop "believe "belief "true + +pprop "bet "belief "true + +pprop "brother "family "true + +pprop "can "priority 0 +pprop "can "rules [[# can I #stuff] g58 [# can you #stuff] g59 [#] g60] +pprop "can "g58 [[You believe I can :stuff, don't you?] how + [You want me to be able to :stuff.] + [Perhaps you would like to be able to :stuff yourself.]] +pprop "can "g59 [[Whether or not you can :stuff depends more on you than on me.] + [Do you want to be able to :stuff?] + [Perhaps you don't want to :stuff.] how] +pprop "can "g60 [how newkey] + +pprop "cant "translation "can't + +pprop "certainly "priority 0 +pprop "certainly "rules [yes] + +pprop "children "family "true + +pprop "computer "priority 50 +pprop "computer "rules [[#] g17] +pprop "computer "g17 [[Do computers worry you?] + [Why do you mention computers?] + [What do you think machines have to do with your problem?] + [Don't you think computers can help people?] + [What about machines worries you?] + [What do you think about machines?]] + +pprop "computers "priority 50 +pprop "computers "rules [computer] + +pprop "dad "translation "father +pprop "dad "family "true + +pprop "daddy "translation "father +pprop "daddy "family "true + +pprop "deutsch "priority 0 +pprop "deutsch "rules [[#] g15] +pprop "deutsch "g15 [[I'm sorry, I speak only English.]] + +pprop "dit "rules [[#] g72] +pprop "dit "g72 [[In what way?] [What resemblance do you see?] + [What does that similarity suggest to you?] + [What other connections do you see?] + [What do you suppose that resemblance means?] + [What is the connection, do you suppose?] + [Could there really be some connection?] how] + +pprop "dont "translation "don't + +pprop "dream "priority 3 +pprop "dream "rules [[#] g9] +pprop "dream "g9 [[What does that dream suggest to you?] [Do you dream often?] + [What persons appear in your dreams?] + [Don't you believe that dream has something to do + with your problem?] + [Do you ever wish you could flee from reality?] newkey] + +pprop "dreamed "priority 4 +pprop "dreamed "rules [[# you dreamed #stuff] g7 [#] g8] +pprop "dreamed "g7 [[Really :stuff?] + [Have you ever fantasied :stuff while you were awake?] + [Have you dreamed :stuff before?] dream newkey] +pprop "dreamed "g8 [dream newkey] + +pprop "dreams "translation "dream +pprop "dreams "priority 3 +pprop "dreams "rules [dream] + +pprop "dreamt "translation "dreamed +pprop "dreamt "priority 4 +pprop "dreamt "rules [dreamed] + +pprop "espanol "priority 0 +pprop "espanol "rules [deutsch] + +pprop "everybody "priority 2 +pprop "everybody "rules [everyone] + +pprop "everyone "priority 2 +pprop "everyone "rules [[# !a:in [everyone everybody nobody noone] #] g68] +pprop "everyone "g68 [[Really, :a?] [Surely not :a.] + [Can you think of anyone in particular?] + [Who, for example?] + [You are thinking of a very special person.] + [Who, may I ask?] [Someone special perhaps.] + [You have a particular person in mind, don't you?] + [Who do you think you're talking about?] + [I suspect you're exaggerating a little.]] + +pprop "father "family "true + +pprop "feel "belief "true + +pprop "francais "priority 0 +pprop "francais "rules [deutsch] + +pprop "hello "priority 0 +pprop "hello "rules [[#] g16] +pprop "hello "g16 [[How do you do. Please state your problem.]] + +pprop "how "priority 0 +pprop "how "rules [[#] g63] +pprop "how "g63 [[Why do you ask?] [Does that question interest you?] + [What is it you really want to know?] + [Are such questions much on your mind?] + [What answer would please you most?] [What do you think?] + [What comes to your mind when you ask that?] + [Have you asked such questions before?] + [Have you asked anyone else?]] + +pprop "husband "family "true + +pprop "i "priority 0 +pprop "i "translation "you +pprop "i "rules [[# you !:in [want need] #stuff] g32 + [# you are # !stuff:in [sad unhappy depressed sick] #] g33 + [# you are # !stuff:in [happy elated glad better] #] g34 + [# you was #] g35 [# you !:beliefp you #stuff] g36 + [# you # !:beliefp # i #] g37 [# you are #stuff] g38 + [# you !:in [can't cannot] #stuff] g39 + [# you don't #stuff] g40 [# you feel #stuff] g41 + [# you #stuff i #] g42 [#stuff] g43] +pprop "i "g32 [[What would it mean to you if you got :stuff?] + [Why Do you want :stuff?] [Suppose you got :stuff soon.] + [What if you never got :stuff?] + [What would getting :stuff mean to you?] [You really want :stuff.] + [I suspect you really don't want :stuff.]] +pprop "i "g33 [[I'm sorry to hear you are :stuff.] + [Do you think coming here will help you not to be :stuff?] + [I'm sure it's not pleasant to be :stuff.] + [Can you explain what made you :stuff?] [Please go on.]] +pprop "i "g34 [[How have I helped you to be :stuff?] + [Has your treatment made you :stuff?] + [What makes you :stuff just now?] + [Can you explain why you are suddenly :stuff?] + [Are you sure?] [What do you mean by :stuff?]] +pprop "i "g35 [was] +pprop "i "g36 [[Do you really think so?] [But you are not sure you :stuff.] + [Do you really doubt you :stuff?]] +pprop "i "g37 [you] +pprop "i "g38 [[Is it because you are :stuff that you came to me?] + [How long have you been :stuff?] + [Do you believe it normal to be :stuff?] [Do you enjoy being :stuff?]] +pprop "i "g39 [[How do you know you can't :stuff?] [Have you tried?] + [Perhaps you could :stuff now.] + [Do you really want to be able to :stuff?]] +pprop "i "g40 [[Don't you really :stuff?] [Why don't you :stuff?] + [Do you wish to be able to :stuff?] [Does that trouble you?]] +pprop "i "g41 [[Tell me more about such feelings.] [Do you often feel :stuff?] + [Do you enjoy feeling :stuff?] + [Of what does feeling :stuff remind you?]] +pprop "i "g42 [[Perhaps in your fantasy we :stuff each other.] + [Do you wish to :stuff me?] [You seem to need to :stuff me.] + [Do you :stuff anyone else?]] +pprop "i "g43 [[You say :stuff.] [Can you elaborate on that?] + [Do you say :stuff for some special reason?] + [That's quite interesting.]] + +pprop "i'm "priority 0 +pprop "i'm "translation "you're +pprop "i'm "rules [[# you're #stuff] g31] +pprop "i'm "g31 [[pre [you are :stuff] I]] + +pprop "if "priority 3 +pprop "if "rules [[#a if #b had #c] g5 [# if #stuff] g6] +pprop "if "g5 [[pre [:a if :b might have :c] if]] +pprop "if "g6 [[Do you think it's likely that :stuff?] [Do you wish that :stuff?] + [What do you think about :stuff?]] + +pprop "is "priority 0 +pprop "is "rules [[&a is &b] g61 [#] g62] +pprop "is "g61 [[Suppose :a were not :b.] [Perhaps :a really is :b.] + [Tell me more about :a.]] +pprop "is "g62 [newkey] + +pprop "italiano "priority 0 +pprop "italiano "rules [deutsch] + +pprop "like "priority 10 +pprop "like "rules [[# !:in [am is are was] # like #] g70 [#] g71] +pprop "like "g70 [dit] +pprop "like "g71 [newkey] + +pprop "machine "priority 50 +pprop "machine "rules [computer] + +pprop "machines "priority 50 +pprop "machines "rules [computer] + +pprop "maybe "priority 0 +pprop "maybe "rules [perhaps] + +pprop "me "translation "you + +pprop "mom "translation "mother +pprop "mom "family "true + +pprop "mommy "translation "mother +pprop "mommy "family "true + +pprop "mother "family "true + +pprop "my "priority 2 +pprop "my "translation "your +pprop "my "rules [[# your # !a:familyp #b] g55 [# your &stuff] g56 [#] g57] +pprop "my "g55 [[Tell me more about your family.] [Who else in your family :b?] + [Your :a?] [What else comes to mind when you think of your :a?]] +pprop "my "g56 [[Your :stuff?] [Why do you say your :stuff?] + [Does that suggest anything else which belongs to you?] + [Is it important to you that your :stuff?]] +pprop "my "g57 [newkey] +pprop "my "memr [[# your &stuff] g12] +pprop "my "g12 [[Earlier you said your :stuff.] [But your :stuff.] + [Does that have anything to do with your statement about :stuff?]] + +pprop "myself "translation "yourself + +pprop "name "priority 15 +pprop "name "rules [[#] g14] +pprop "name "g14 [[I am not interested in names.] + [I've told you before I don't care about names\; please continue.]] + +pprop "no "priority 0 +pprop "no "rules [[no] g53 [#] g54] +pprop "no "g53 [xxyyzz [pre [x no] no]] +pprop "no "g54 [[Are you saying "no" just to be negative?] + [You are being a bit negative.] [Why not?] [Why "no"?] newkey] + +pprop "nobody "priority 2 +pprop "nobody "rules [everyone] + +pprop "noone "priority 2 +pprop "noone "rules [everyone] + +pprop "perhaps "priority 0 +pprop "perhaps "rules [[#] g13] +pprop "perhaps "g13 [[You don't seem quite certain.] [Why the uncertain tone?] + [Can't you be more positive?] [You aren't sure.] + [Don't you know?]] + +pprop "problem "priority 5 +pprop "problem "rules [[#a !b:in [is are] your !c:in [problem problems] #] g73 + [# your !a:in [problem problems] !b:in [is are] #c] g74 + [#] g75] +pprop "problem "g73 [[:a :b your :c.] [Are you sure :a :b your :c?] + [Perhaps :a :b not your real :c.] + [You think you have problems?] + [Do you often think about :a?]] +pprop "problem "g74 [[Your :a :b :c?] [Are you sure your :a :b :c?] + [Perhaps your real :a :b not :c.] [You think you have problems?]] +pprop "problem "g75 [[Please continue, this may be interesting.] + [Have you any other problems you wish to discuss?] + [Perhaps you'd rather change the subject.] + [You seem a bit uneasy.] newkey] +pprop "problem "memr [[#stuff is your problem #] g76] +pprop "problem "g76 [[Earlier you mentioned :stuff.] + [Let's talk further about :stuff.] + [Tell me more about :stuff.] + [You haven't mentioned :stuff for a while.]] + +pprop "problems "priority 5 +pprop "problems "rules [problem] + +pprop "remember "priority 5 +pprop "remember "rules [[# you remember #stuff] g2 [# do I remember #stuff] g3 [#] g4] +pprop "remember "g2 [[Do you often think of :stuff?] + [Does thinking of :stuff bring anything else to mind?] + [What else do you remember?] + [Why do you remember :stuff just now?] + [What in the present situation reminds you of :stuff?]] +pprop "remember "g3 [[Did you think I would forget :stuff?] + [Why do you think I should recall :stuff now?] + [What about :stuff?] what [You mentioned :stuff.]] +pprop "remember "g4 [newkey] + +pprop "same "priority 10 +pprop "same "rules [dit] + +pprop "sister "family "true + +pprop "sorry "priority 0 +pprop "sorry "rules [[#] g1] +pprop "sorry "g1 [[Please don't apologize.] [Apologies are not necessary.] + [What feelings do you have when you apologize?] + [I've told you that apologies are not required.]] + +pprop "svenska "priority 0 +pprop "svenska "rules [deutsch] + +pprop "think "belief "true + +pprop "was "priority 2 +pprop "was "rules [[# was you #stuff] g26 [# you was #stuff] g27 + [# was I #stuff] g28 [#] g29] +pprop "was "g26 [[What if you were :stuff?] [Do you think you were :stuff?] + [Were you :stuff?] [What would it mean if you were :stuff?] + [What does " :stuff " suggest to you?] how] +pprop "was "g27 [[Were you really?] [Why do you tell me you were :stuff now?] + [Perhaps I already knew you were :stuff.]] +pprop "was "g28 [[Would you like to believe I was :stuff?] + [What suggests that I was :stuff?] [What do you think?] + [Perhaps I was :stuff.] [What if I had been :stuff?]] +pprop "was "g29 [newkey] + +pprop "we "translation "you +pprop "we "priority 0 +pprop "we "rules [I] + +pprop "were "priority 0 +pprop "were "translation "was +pprop "were "rules [was] + +pprop "what "priority 0 +pprop "what "rules [[!:in [what where] #] g10 [# !a:in [what where] #b] g11] +pprop "what "g10 [how] +pprop "what "g11 [[Tell me about :a :b.] [:a :b?] [Do you want me to tell you :a :b?] + [Really.] [I see.] newkey] + +pprop "where "priority 0 +pprop "where "rules [how] + +pprop "why "priority 0 +pprop "why "rules [[# why don't I #stuff] g65 [# why can't you #stuff] g66 [#] g67] +pprop "why "g65 [[Do you believe I don't :stuff?] + [Perhaps I will :stuff in good time.] + [Should you :stuff yourself?] [You want me to :stuff?] how] +pprop "why "g66 [[Do you think you should be able to :stuff?] + [Do you want to be able to :stuff?] + [Do you believe this will help you to :stuff?] + [Have you any idea why you can't :stuff?] how] +pprop "why "g67 [[Why indeed?] [Why "why"?] [Why not?] how newkey] + +pprop "wife "family "true + +pprop "wish "belief "true + +pprop "wont "translation "won't + +pprop "xxyyzz "priority 0 +pprop "xxyyzz "rules [[#] g50] +pprop "xxyyzz "g50 [[You're being somewhat short with me.] + [You don't seem very talkative today.] + [Perhaps you'd rather talk about something else.] + [Are you using monosyllables for some reason?] newkey] + +pprop "yes "priority 0 +pprop "yes "rules [[yes] g51 [#] g52] +pprop "yes "g51 [xxyyzz [pre [x yes] yes]] +pprop "yes "g52 [[You seem quite positive.] [You are sure.] [I see.] + [I understand.] newkey] + +pprop "you "priority 0 +pprop "you "translation "I +pprop "you "rules [[# I remind you of #] g44 [# I are # you #] g45 + [# I # are #stuff] g46 [# I #stuff you] g47 + [# I &stuff] g48 [#] g49] +pprop "you "g44 [dit] +pprop "you "g45 [newkey] +pprop "you "g46 [[What makes you think I am :stuff?] + [Does it please you to believe I am :stuff?] + [Perhaps you would like to be :stuff.] + [Do you sometimes wish you were :stuff?]] +pprop "you "g47 [[Why do you think I :stuff you?] + [You like to think I :stuff you, don't you?] + [What makes you think I :stuff you?] [Really, I :stuff you?] + [Do you wish to believe I :stuff you?] + [Suppose I did :stuff you. what would that mean?] + [Does someone else believe I :stuff you?]] +pprop "you "g48 [[We were discussing you, not me.] [Oh, I :stuff?] + [Is this really relevant to your problem?] [Perhaps I do :stuff.] + [Are you glad to know I :stuff?] [Do you :stuff?] + [What are your feelings now?]] +pprop "you "g49 [newkey] + +pprop "you're "priority 0 +pprop "you're "translation "I'm +pprop "you're "rules [[# I'm #stuff] g30] +pprop "you're "g30 [[pre [I are :stuff] you]] + +pprop "your "priority 0 +pprop "your "translation "my +pprop "your "rules [[# my #stuff] g25] +pprop "your "g25 [[Why are you concerned over my :stuff?] + [What about your own :stuff?] + [Are you worried about someone else's :stuff?] + [Really, my :stuff?]] + +pprop "yourself "translation "myself + + +to match :pat :sen +local [special.var special.pred special.buffer in.list] +if or wordp :pat wordp :sen [output "false] +if emptyp :pat [output emptyp :sen] +if listp first :pat [output special fput "!: :pat :sen] +if memberp first first :pat [? # ! & @ ^] [output special :pat :sen] +if emptyp :sen [output "false] +if equalp first :pat first :sen [output match butfirst :pat butfirst :sen] +output "false +end + +;; Parsing quantifiers + +to special :pat :sen +set.special parse.special butfirst first :pat " +output run word "match first first :pat +end + +to parse.special :word :var +if emptyp :word [output list :var "always] +if equalp first :word ": [output list :var butfirst :word] +output parse.special butfirst :word word :var first :word +end + +to set.special :list +make "special.var first :list +make "special.pred last :list +if emptyp :special.var [make "special.var "special.buffer] +if memberp :special.pred [in anyof] [set.in] +if not emptyp :special.pred [stop] +make "special.pred first butfirst :pat +make "pat fput first :pat butfirst butfirst :pat +end + +to set.in +make "in.list first butfirst :pat +make "pat fput first :pat butfirst butfirst :pat +end + +;; Exactly one match + +to match! +if emptyp :sen [output "false] +if not try.pred [output "false] +make :special.var first :sen +output match butfirst :pat butfirst :sen +end + +;; Zero or one match + +to match? +make :special.var [] +if emptyp :sen [output match butfirst :pat :sen] +if not try.pred [output match butfirst :pat :sen] +make :special.var first :sen +if match butfirst :pat butfirst :sen [output "true] +make :special.var [] +output match butfirst :pat :sen +end + +;; Zero or more matches + +to match# +make :special.var [] +output #test #gather :sen +end + +to #gather :sen +if emptyp :sen [output :sen] +if not try.pred [output :sen] +make :special.var lput first :sen thing :special.var +output #gather butfirst :sen +end + +to #test :sen +if match butfirst :pat :sen [output "true] +if emptyp thing :special.var [output "false] +output #test2 fput last thing :special.var :sen +end + +to #test2 :sen +make :special.var butlast thing :special.var +output #test :sen +end + +;; One or more matches + +to match& +output &test match# +end + +to &test :tf +if emptyp thing :special.var [output "false] +output :tf +end + +;; Zero or more matches (as few as possible) + +to match^ +make :special.var [] +output ^test :sen +end + +to ^test :sen +if match butfirst :pat :sen [output "true] +if emptyp :sen [output "false] +if not try.pred [output "false] +make :special.var lput first :sen thing :special.var +output ^test butfirst :sen +end + +;; Match words in a group + +to match@ +make :special.var :sen +output @test [] +end + +to @test :sen +if @try.pred [if match butfirst :pat :sen [output "true]] +if emptyp thing :special.var [output "false] +output @test2 fput last thing :special.var :sen +end + +to @test2 :sen +make :special.var butlast thing :special.var +output @test :sen +end + +;; Applying the predicates + +to try.pred +if listp :special.pred [output match :special.pred first :sen] +output run list :special.pred quoted first :sen +end + +to quoted :thing +if listp :thing [output :thing] +output word "" :thing +end + +to @try.pred +if listp :special.pred [output match :special.pred thing :special.var] +output run list :special.pred thing :special.var +end + +;; Special predicates + +to always :x +output "true +end + +to in :word +output memberp :word :in.list +end + +to anyof :sen +output anyof1 :sen :in.list +end + +to anyof1 :sen :pats +if emptyp :pats [output "false] +if match first :pats :sen [output "true] +output anyof1 :sen butfirst :pats +end -- cgit 1.4.1-2-gfad0