diff options
author | elioat <elioat@tilde.institute> | 2023-08-23 07:52:19 -0400 |
---|---|---|
committer | elioat <elioat@tilde.institute> | 2023-08-23 07:52:19 -0400 |
commit | 562a9a52d599d9a05f871404050968a5fd282640 (patch) | |
tree | 7d3305c1252c043bfe246ccc7deff0056aa6b5ab /js/games/nluqo.github.io/~bh/v2ch9 | |
parent | 5d012c6c011a9dedf7d0a098e456206244eb5a0f (diff) | |
download | tour-562a9a52d599d9a05f871404050968a5fd282640.tar.gz |
*
Diffstat (limited to 'js/games/nluqo.github.io/~bh/v2ch9')
-rw-r--r-- | js/games/nluqo.github.io/~bh/v2ch9/doctor.html | 1641 | ||||
-rw-r--r-- | js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif | bin | 0 -> 7225 bytes | |||
-rw-r--r-- | js/games/nluqo.github.io/~bh/v2ch9/doctormatch.lg | 794 |
3 files changed, 2435 insertions, 0 deletions
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 @@ +<HTML> +<HEAD> +<TITLE>Computer Science Logo Style vol 2 ch 9: Example: Doctor</TITLE> +</HEAD> +<BODY> +<CITE>Computer Science Logo Style</CITE> volume 2: +<CITE>Advanced Techniques</CITE> 2/e Copyright (C) 1997 MIT +<H1>Example: Doctor</H1> + +<TABLE width="100%"><TR><TD> +<IMG SRC="../csls2.jpg" ALT="cover photo"> +<TD><TABLE> +<TR><TD align="right"><CITE><A HREF="http://www.cs.berkeley.edu/~bh/">Brian +Harvey</A><BR>University of California, Berkeley</CITE> +<TR><TD align="right"><BR> +<TR><TD align="right"><A HREF="../pdf/v2ch09.pdf">Download PDF version</A> +<TR><TD align="right"><A HREF="../v2-toc2.html">Back to Table of Contents</A> +<TR><TD align="right"><A HREF="../v2ch8/v2ch8.html"><STRONG>BACK</STRONG></A> +chapter thread <A HREF="../v2ch10/v2ch10.html"><STRONG>NEXT</STRONG></A> +<TR><TD align="right"><A HREF="https://mitpress.mit.edu/books/computer-science-logo-style-second-edition-volume-2">MIT +Press web page for <CITE>Computer Science Logo Style</CITE></A> +</TABLE></TABLE> + +<HR><P>Program file for this chapter: <A HREF="doctormatch.lg"><CODE>doctor</CODE></A> + + + +<P><PRE>? <U>doctor</U> +Hello, I am the doctor. What can i do for you? +Please end your remarks with an empty line. + +<U>My spirits are low.</U> + +Your spirits are low? + +<U>I'm really depressed.</U> + +I'm sorry to hear you are depressed. + +<U>It's because nobody likes me.</U> + +Really, nobody? + +<U>That's right.</U> + +I am not sure I understand you fully. + +<U>I'm lonely.</U> + +Is it because you are lonely that you came to me? + +<U>Of course.</U> + +Earlier you said your spirits are low. +</PRE> + +<P>This is the beginning of a dialogue with a program called <CODE>doctor</CODE>. 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 <EM>rules;</EM> 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 + +<P><PRE>[# !a:in [everyone everybody nobody noone] #] +</PRE> + +<P>Corresponding to that pattern is a list of responses: + +<P><PRE>[[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.]] +</PRE> + +<P>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. + +<P>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 <EM>Pygmalion</EM> 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. + +<BLOCKQUOTE><P> +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. + +<P> +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... +<P> +[Joseph Weizenbaum, <EM>Computer Power and Human Reason</EM> (Freeman, 1976), +page 3.] +</BLOCKQUOTE> + +<P> +It has long been a popular Logo programming project to implement a small +subset of <CODE>doctor</CODE>'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, <EM>Apple Logo</EM> (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. + +<P>You should try conversing with <CODE>doctor</CODE> 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. + +<P><H2>Eliza and Artificial Intelligence</H2> + +<P>When Eliza was first unveiled, many people considered it a major advance in +the pursuit of <EM>artificial intelligence:</EM> 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." + +<P>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, <EM>Computer Power and Human Reason</EM>, from which I quoted a passage +earlier. He argues not only that computers <EM>cannot</EM> do certain +things, but also that people <EM>should not</EM> 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. + +<P><H2>Eliza's Linguistic Strategy</H2> + +<P>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: + +<P> +<OL><LI> Find the punctuation in the input and use it to extract a single +sentence to answer. +<LI> Find keywords in the sentence for which the script includes rules. +<LI> 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. +<LI> Pick the highest priority keyword. +<LI> Find a rule for that keyword whose pattern matches the input +sentence. +<LI> Choose a response according to that rule. +</OL><P> + +<P>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. + +<P>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 <EM>memory</EM> 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. + +<P>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 +<EM>another</EM> 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 <CODE>if</CODE> instructions that check for these +special cases and concentrate on the usual situation. + +<P>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 <CODE>doctor</CODE> does +some initialization and then invokes <CODE>loop</CODE>, which does the real work. + +<P><CENTER><IMG SRC="doctorflow.gif" ALT="figure: doctorflow"></CENTER> + +<P><PRE>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 +</PRE> + +<P><CODE>Loop</CODE> uses <CODE>getstuff</CODE> to read several lines of the user's +typing into a long list. This list is processed by several procedures in +turn. + +<P><PRE>to getstuff :stuff +localmake "line readlist +if emptyp :line [output :stuff] +output getstuff sentence :stuff :line +end +</PRE> + +<P>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 <CODE>tokenize</CODE> and its subprocedure <CODE> +tokenword</CODE>. (These procedures get their name from the computer scientist's +term <EM>token</EM>, which means the smallest possible meaningful string of +characters. In the BASIC compiler of Chapter 6, the procedure called +<CODE>reader</CODE> separates a line of text into tokens.) + +<P><PRE>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 +</PRE> + +<P>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. <CODE> +tokenword</CODE> turns a word like <CODE>why?</CODE> into the two-word list <CODE>[why .]</CODE> +so that the period as a separate word serves as the separator between +sentences in the long list. + +<P>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 +<CODE>getsentence</CODE>, which uses <CODE>checkpriority</CODE> and <CODE>translate</CODE> 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 <CODE>decapitalize</CODE> that turns the first letter of +each sentence to lower case, and when the program prints a +response it uses the inverse procedure <CODE>capitalize</CODE> 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.) + +<P><PRE>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 +</PRE> + +<P>At each sentence separator (a word containing only a period), <CODE> +getsentence1</CODE> checks whether any keywords have been found yet. If so, the +sentence before the separator is the one the program uses. If not, <CODE> +getsentence1</CODE> 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. + +<P> + +<P>Both <CODE>checkpriority</CODE> and <CODE>translate</CODE> work through the use of +property lists that are associated with words. The script part of +<CODE>doctor</CODE> (Weizenbaum's second tier) consists of these property lists. +For example, here's part of the script setup: + +<P><PRE>pprop "my "priority 2 +pprop "my "translation "your +</PRE> + +<P> + +<P>The first of these means that <CODE>my</CODE> is a keyword, with priority +2. In the Doctor script, most keywords have priority 0. <CODE>My</CODE> is a +little more important than most words, but not as important as <CODE>dreamed</CODE> +(priority 4) or <CODE>computer</CODE> (priority 50)! <CODE>Checkpriority</CODE> arranges +the list of keywords so that the word with highest priority is first in the +list. The <CODE>translation</CODE> property means that the word <CODE>my</CODE> is +changed to <CODE>your</CODE> 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 +<CODE>checkpriority</CODE> has <EM>untranslated</EM> keywords. That's why the +patterns associated with the keyword <CODE>you</CODE>, for example, all contain +the word <CODE>I</CODE> instead; the patterns deal with the translated version.) + +<P>Step 4, finding the highest priority keyword, is simply a matter of choosing +the <CODE>first</CODE> keyword in the list because of the way <CODE>checkpriority</CODE> +has done its job. This selection is made by <CODE>analyze</CODE>, which then +invokes <CODE>checkrules</CODE> as a subprocedure. (<CODE>Analyze</CODE> also recognizes +the special situation in which one keyword refers to the rules of another.) + +<P><PRE>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 +</PRE> + +<P><CODE>Checkrules</CODE> handles step 5, finding an applicable rule for the chosen +keyword. That is, <CODE>checkrules</CODE> invokes <CODE>match</CODE> 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 <CODE>[#]</CODE> as the pattern +in the last rule.) When <CODE>checkrules</CODE> finds a matching pattern, it +invokes <CODE>dorule</CODE> to examine the corresponding list of responses. (One +complication in understanding these procedures is that the input to <CODE> +dorule</CODE> is <EM>the name of a property</EM> 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 <CODE>dorule</CODE> chooses one of the +responses and uses it as the input to <CODE>reconstruct</CODE>.) + +<P><PRE>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 +</PRE> + +<P>The usual task of <CODE>dorule</CODE> is to carry out step 6, the generation of a +response. For example, when the user typed + +<P><PRE>My spirits are low. +</PRE> + +<P>the highest priority keyword found was <CODE>my</CODE>. There are three +patterns associated with this keyword: + +<P><PRE>[# your # !a:familyp #b] +[# your &stuff] +[#] +</PRE> + +<P>(Again, the pattern is matched against the sentence <EM>after</EM> +translation, so the patterns contain the word <CODE>your</CODE> even though the +actual keyword is <CODE>my</CODE>.) The first of these patterns does not match the +sentence. (<CODE>Familyp</CODE> is a predicate that's true for words like <CODE> +mother</CODE> and <CODE>brother</CODE>.) The second pattern, however, does match the +sentence. <CODE>Match</CODE> gives the variable <CODE>stuff</CODE> the list + +<P><PRE>[spirits are low] +</PRE> + +<P>as its value. (The period that ended what the user typed was +removed by <CODE>tokenize</CODE>.) + +<P>Associated with that second pattern is this list of responses: + +<P><PRE>[[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?]] +</PRE> + +<P><CODE>Dorule</CODE> chooses the first of these, and invokes <CODE> +reconstruct</CODE> 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," <CODE>reconstruct</CODE> isn't exactly like the Logo +interpreter. For one thing, it recognizes punctuation marks; it knows that +this response refers to a variable named <CODE>stuff</CODE>, not <CODE>stuff?</CODE>. + +<P><PRE>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 +</PRE> + +<P><H2>Stimulus-Response Psychology</H2> + +<P>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 <EM>people</EM> 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 <EM>model</EM> 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." + +<P>Weizenbaum's work on Eliza is an early example of the former approach. He +was emphatically <EM>not</EM> claiming that his program worked the way people +work. Indeed, one of the purposes of the program was to demonstrate how +realistic the <EM>behavior</EM> of a computer program can be, even when we +are quite sure that the underlying <EM>mechanism</EM> is completely +unrealistic. + +<P>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 +<EM>behaviorism,</EM> or the <EM>stimulus-response</EM> theory. +According to this theory, a person's mind is a "black box," and we can't +know what's inside. What we <EM>can</EM> know, however, is how a person +reacts to different situations and events. Whatever situation presents +itself to you is called a <EM>stimulus</EM>. 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 <EM>response</EM>: 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 <EM>conditioning</EM> +techniques. If you are rewarded for producing a certain response, you'll +produce it more often. + +<P>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 <CODE>match</CODE> and its subprocedures +are a substantial part of the complete <CODE>doctor</CODE> program. The second +part, the one that produces responses, is <CODE>dorule</CODE> and <CODE>reconstruct</CODE>. + +<P>Eliza does not represent a very sophisticated form of stimulus-response +theory because it leaves out the idea of <EM>learning</EM>. 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. + +<P>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 <EM>and</EM> 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. + +<P><H2>Property Lists</H2> + +<P>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 +<CODE>my</CODE> looks like this: + +<P> + +<P><PRE>[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?]]] +</PRE> + +<P>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 <CODE>my</CODE> has properties named +<CODE>priority</CODE>, <CODE>translation</CODE>, <CODE>rules</CODE>, <CODE>g1</CODE>, <CODE>g2</CODE>, <CODE> +g3</CODE>, <CODE>memr</CODE>, and <CODE>g4</CODE>. The <CODE>priority</CODE> and <CODE>translation</CODE> +properties are straightforward. The <CODE>rules</CODE> and <CODE>memr</CODE> 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. + +<P>To create these property lists, I used <CODE>pprop</CODE> 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. + +<P><PRE>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?]] +</PRE> + +<P>In general, the order in which properties are added to the list +doesn't matter. However, the order of the <CODE>addrule</CODE> instructions <EM> +does</EM> matter, because the rule that's added first is the one that +<CODE>checkrules</CODE> 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. + +<P> + +<P><H2>Generated Symbols</H2> + + + + +<P>The procedures <CODE>addrule</CODE> and <CODE>addmemr</CODE> are very similar, since the +<CODE>rules</CODE> and <CODE>memr</CODE> properties are similar in format. + +<P><PRE>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 +</PRE> + +<P>Each of these procedures uses a local variable <CODE>propname</CODE> to +contain the name of the response property, a "generated symbol" or <EM> +gensym.</EM> These are the words like <CODE>g3</CODE> in the example above. Each +procedure carries out two <CODE>pprop</CODE> instructions. The first appends a new +pattern and a new gensym to the previous value of the <CODE>rules</CODE> or <CODE> +memr</CODE> property; the second creates a new property with the gensym as its +name and the response (or memory) list as its value. <CODE>Gensym</CODE> is +a Berkeley Logo library procedure. + +<P><H2>Modification of List Structure</H2> + + + +<P>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 <CODE>rules</CODE>. It's as if +the Logo property list looked like this: + +<P> + +<P><PRE>[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?]]] +] +</PRE> + +<P>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. + +<P>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..." + +<P>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, <CODE>dorule</CODE> contains the +instructions + +<P><PRE>localmake "print first gprop :keyword :rule +pprop :keyword :rule lput :print butfirst gprop :keyword :rule +</PRE> + +<P>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 <CODE>lput</CODE> behind the remaining +ones. + +<P> + +<P>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 <CODE>rules</CODE> property had as its value this +list: + +<P><PRE>[1 [A B C] 2 [D E F] 3 [G H I]] +</PRE> + +<P>In this example, the numbers represent patterns, while the letters +represent responses. Now suppose that the program finds a match for pattern +number <CODE>2</CODE>. It should then issue the response <CODE>D</CODE>. Then it +should rotate the three responses associated with pattern <CODE>2</CODE> so that +the new <CODE>rules</CODE> property is + +<P><PRE>[1 [A B C] 2 [E F D] 3 [G H I]] +</PRE> + +<P>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: + +<P><PRE>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 +</PRE> + +<P>You'd use this program with an instruction like + +<P><PRE>rotate "word 2 +</PRE> + +<P>where <CODE>2</CODE> represents the pattern in the example above. + +<P>The trouble with this approach is that it's slow. It does a lot of <CODE> +list</CODE> and <CODE>sentence</CODE> operations to reconstruct the modified list. +More importantly, the <EM>entire</EM> list must be copied, even though +only one rule is to be modified. + +<P> +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 <CODE>.setfirst</CODE> and <CODE>.setbutfirst</CODE>; using +them, we could write <CODE>rotate</CODE> this way: + +<P><PRE>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 +</PRE> + +<P>(I'll leave <CODE>rotate2</CODE> 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: + +<P><PRE>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]] +</PRE> + +<P>In the lower-level invocation of <CODE>rotate1</CODE>, the <CODE>equalp</CODE> +test outputs <CODE>true</CODE>, so the <CODE>ifelse</CODE> instruction evaluates its second +input. This is equivalent to the instruction + +<P><PRE>.setfirst [[D E F] 3 [G H I]] (rotate2 [D E F]) +</PRE> + +<P>or + +<P><PRE>.setfirst [[D E F] 3 [G H I]] [E F D] +</PRE> + +<P>To understand what this means, you must realize that the primitive operation +<CODE>butfirst</CODE> does not make a <EM>copy</EM> of the butfirst of its input. +Instead, the list output by <CODE>butfirst</CODE> 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 <CODE>butfirst</CODE> also changes the larger +list. The <CODE>setfirst</CODE> instruction ends up changing the <CODE>rules</CODE> +property of the word <CODE>word</CODE> even though there is no explicit <CODE> +pprop</CODE> to change the property. + +<P>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 + +<P><PRE>.setfirst [[D E F] 3 [G H I]] [E F D] +</PRE> + +<P>explicitly at top level, it would <EM>not</EM> change the property +list of <CODE>word</CODE>, because the list that <CODE>setfirst</CODE> modifies would <EM> +not</EM> be part of that property list, even though it has the same members. +It's only because <CODE>setfirst</CODE>'s input is derived from that property list +by a series of <CODE>butfirst</CODE> operations that they share the same memory. + +<P> + +<P>Do you find this confusing? The original designers of Logo chose not to include +<CODE>.setfirst</CODE> in the language because it <EM>is</EM> hard to understand, and +because it can produce some very strange results if you're not careful with +it. For example, consider these instructions: + +<P><PRE>make "c [x y] +.setfirst (butfirst :c) (:c) +</PRE> + +<P>This <CODE>.setfirst</CODE> instruction will produce a <EM> +circular list</EM>, one that contains itself as a member. If you try +to print <CODE>:c</CODE>, you'll see something like + +<P><PRE>[x [x [x [x [x [x [x [x [x [x [x [x [x [x [x ... +</PRE> + +<P>going on forever. + +<P>Once we have these list modification tools, even the implicit recopying +done by <CODE>lput</CODE> can be avoided. Here's a more efficient version of +<CODE>rotate1</CODE>, but it's really tricky to understand and it isn't a +technique that I recommend: + +<P><PRE> +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 +</PRE> + +<P>In <CODE>rotate2</CODE>, the <CODE>.setfirst</CODE> instruction removes +the first response from the head of the list of responses; the two +<CODE>.setbutfirst</CODE> instructions "splice" that first response back +into the list at the end, following what used to be the last +response. + +<P> +Leaving <CODE>.setfirst</CODE> 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. + +<P> + +<P>In any case, since Logo didn't have <CODE>.setfirst</CODE> and I didn't want the +<CODE>doctor</CODE> program to be slowed down by having to recopy the <CODE>rules</CODE> +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 <CODE> +dorule</CODE> 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. + +<P><H2>Linguistic Structure</H2> + +<P>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 <CODE>I</CODE>: + +<P><PRE>[# you are # !stuff:in [sad unhappy depressed sick] #] +</PRE> + +<P>(Remember that the pattern is matched against the input sentence +after translation, so the words <CODE>you are</CODE> in the pattern really match a +sentence containing the words <CODE>I am</CODE>.) The purpose of the pattern is to +match a sentence like + +<P><PRE>I think I am really depressed because Susan doesn't like me. +</PRE> + +<P>The response of the program might be + +<P><PRE>I'm sorry to hear you are depressed. +</PRE> + +<P>The <CODE>#</CODE> between <CODE>are</CODE> and <CODE>!stuff</CODE> in the pattern is meant to +catch adverbs like the word <CODE>really</CODE> in the example I just gave. But it +could also "absorb" some more structurally important parts of a sentence: + +<P><PRE>I am sure that I would be depressed if she left me. +</PRE> + +<P>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. + +<P>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 <CODE> +depressed</CODE> with the word <CODE>am</CODE> 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 + +<P><PRE>[[subject I] [predicate [[verb am] [nominative [[adjective sure] + [adverb [clause [[connective that] [subject I] [verb [would be] ... +</PRE> + +<P>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). + +<P><H2>Further Explorations</H2> + +<P>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 <CODE>doctor</CODE>, see if you can +think of a new rule that would solve that case without messing up other +sentences. + +<P>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? + +<P>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. + +<P> +<TABLE width="100%"><TR><TD><A HREF="../v2-toc2.html">(back to Table of Contents)</A> +<TD align="right"><A HREF="../v2ch8/v2ch8.html"><STRONG>BACK</STRONG></A> +chapter thread <A HREF="../v2ch10/v2ch10.html"><STRONG>NEXT</STRONG></A> +</TABLE> + +<P><H2>Program Listing</H2> + +<P>The procedures from the pattern matcher of Chapter 7 are included in +this program, but they are not listed again here. + +<P><PRE> +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 +</PRE> + +<P><A HREF="../v2-toc2.html">(back to Table of Contents)</A> +<P><A HREF="../v2ch8/v2ch8.html"><STRONG>BACK</STRONG></A> +chapter thread <A HREF="../v2ch10/v2ch10.html"><STRONG>NEXT</STRONG></A> + +<P> +<ADDRESS> +<A HREF="../index.html">Brian Harvey</A>, +<CODE>bh@cs.berkeley.edu</CODE> +</ADDRESS> +</BODY> +</HTML> 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 --- /dev/null +++ b/js/games/nluqo.github.io/~bh/v2ch9/doctorflow.gif Binary files differdiff --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 |