4.12.2 An ELIZA-like Conversation Program
4.12.2 An ELIZA-like Conversation Program
ELIZA is a conversational program written in the 1960s. It is a program that dazzled the scientific community of the 1960s by showing that it is possible to write computer programs that can converse in a natural human language such as English. However, we soon see that the techniques used were very simple and the claims computer scientist made on the basis of ELIZA’s performance were hyperbolic to a great extent.
ELIZA is a program that behaves like a psychiatrist. The program chats with a psychiatric “patient.” The “patient” types in a sentence in natural language and the program responds to it appropriately. Here is an actual sample of conversation with the original ELIZA program written at MIT by Weizenbaum [Bod87].
input> Men are all alike
IN WHAT WAY
input> They're are always bugging us about something or other
CAN YOU THINK OF A SPECIFIC EXAMPLE
input> Well my boyfriend made me come here
YOUR BOYFRIEND MADE YOU COME HERE
input> He says I am depressed most of the time.
I AM SORRY TO HEAR YOU ARE DEPRESSED
input> It's true. I'm unhappy.
DOES THAT HAVE ANYTHING TO DO WITH THE FACT THAT
YOUR BOYFRIEND MADE YOU COME HERE
input> I need some help that much seems certain.
WHAT WOULD IT MEAN TO YOU IF YOU
GOT SOME HELP THAT MUCH SEEMS CERTAIN.
input> Perhaps I could learn to get along with my mother.
WHY DO YOU SAY YOUR MOTHER.
Our goal now is to write a program that illustrates how ELIZA was written. Our version of ELIZA is not as sophisticated as the original ELIZA in conversational ability. ELIZA is written based on the concept of rules. A rule is simply a data structure or list that has two parts to it—the left hand side (LHS) and the right hand side (RHS). The LHS and RHS can be anything including strings. A rule-based program has a set of rules called a rule base. The program examines the rule base starting from the top. It compares the LHS of a rule to the current state or context of the program and takes an action if the comparison gives a positive response. This state can be complex, but is
usually as simple as a string of words. Let us assume it is a string of words for the purpose of our discussion.
The rule-based program compares or pattern matches the context string with the LHSs of the rules in the rule base one by one. The first rule whose LHS matches in some way with the context string is fired by the program. This simply means that the program takes an action based on the content of the RHS of the fired or triggered rule. This action can be as simple as doing variable interpolation in the RHS string and then printing it.
In fact, the original ELIZA program and the ELIZA program we present here work in this manner. We have a set of rules or a rule base for ELIZA. For the illustration program, the rule base has only three rules. The program can be made more sophisticated by adding more rules and by adding simple morphological processing to it. Let us call the file that contains the rule ElizaRules.dat. The file’s contents are show below.
/I\b(.+)\byou\./ && $1 => /If you $1 me, I $1 you too\./
/I\b(.+)\byou\b(.+)\./ && $1 && $2 => /We $1 you $2 too\./
/I\s+love\s+your\b(.+)\./ && $1 => /Your $1 is beautiful too. You are simply wonderful!/
Each line of this file is a rule. We impose a syntax on each rule. The rule’s LHS and RHS are separated by =>. Each LHS has a pattern expression followed by one or more numbered scalar variables separated by two ampersands (&&). Let us take the first rule. The LHS is
/I\b(.+)\byou\./ && $1
and the RHS is
/If you $1 me, I $1 you too\./
The first part of the LHS
/I\b(.+)\byou\./
matches with an input sentence typed on the terminal such as
I love you.
or
I do love you.
\b stands for the word-boundary anchor. The group inside the parentheses can match any number of words. The part of the input sentence that matches the group is remembered as the value of the variable $1. The second part of the LHS is $1 separated from the regular expression by &&. && is used in Perl as the anding operator in addition to and. This LHS
is used to test to see if the pattern
/I\b(.+)\byou\./
matches with the input sentence such that $1 is assigned a non-null value.
Let us suppose the input sentence is
I do love you.
So, there is a match between the input sentence and the pattern and the value of $1 is do love. Now, let us look at the RHS of this rule.
/If you $1 me, I $1 you too\./
If the value of $1 is substituted into the RHS expression, we get
If you do love me, I do love you too.
ELIZA produces this sentence as the output for the input sentence
I do love you.
That is, when ELIZA’s patient says
I do love you.
ELIZA, the psychiatrist program responds by printing
If you do love me, I do love you too.
Similarly, each of the other two rules in our rule base is designed to produce an output corresponding to a certain sentence type. The ELIZA program compares the input sentence with each rule one by one. The first rule that matches with the assignment of values to the appropriate number of special number variables is used to produce ELIZA’s output.
Now that we have discussed how ELIZA behaves, we look at the actual code.
Program 4.48
#!/usr/bin/perl
print "I am Eliza, a psychiatrist.\n";
print "Please say something to me.\n";
print "Say `Bye' to finish.\n\n";
NEXT_INPUT:
while ($userInput = ){
chomp ($userInput);
if ($userInput =~ /^Bye/i){ #IF-1
print "Thanks!\nSee you again soon!\n";
last NEXT_INPUT;
} #IF-1 ends
else{ #ELSE-1
open (RULES, "ElizaRules.dat");
while ($rule = ){ #WHILE-2
chomp ($rule);
($lhs, $rhs) = split ('\s*=>\s*', $rule);
$patternMatchCode = '($userInput =~ ' . $lhs . ')';
if (eval $patternMatchCode){ #IF-2
($substitutionLeft) = ( $lhs =~ m#(/.+)/# );
$substitutionCode =
'$userInput =~ ' . 's' . $substitutionLeft . $rhs;
eval $substitutionCode;
$systemOutput = trimSpace ($userInput);
print "$systemOutput\n";
next NEXT_INPUT;
} #IF-2 ends
} #WHILE-2 ends
#No more rules in rulebase
print "Please go on!\n";
close (RULES);
} #ELSE-1 ends
}
close (RULES);
#If there are more than one blank spaces between the words in
#a string, remove them so that there is only one blank space
#between two words
sub trimSpace
{
my $input = $_[0];
$input =~ s/\s+(\w+)\s+/ $1 /g;
return $input;
}
The program prints some preliminary statements and goes into a while loop where it reads an input from the user and responds to it till the user types in bye or a variation of it.
The processing of the user input happens in the else block of the if-else statement on the top of the main while loop. The program opens the file ElizaRules.dat that contains the rule base. It reads each rule one by one inside the embedded while loop. It reads a rule and immediately splits it up using Perl’s split function, using
=> as the splitting boundary. This gives us the LHS and the RHS of the rule, called $lhs and $rhs, respectively, inside the program.
The user’s input sentence is stored in the variable $userInput. The program constructs a string called $patternMatchCode that it executes later. This code is constructed using string concatenation.
$patternMatchCode = '($userInput =~ ' . $lhs . ')';
The string that is constructed has the LHS of the rule in it. So, $patternMatchCode looks something like
$userInput =~ /I\b(.+)\byou\./ && $1
assuming the first rule is being processed. Next, we have an if block with the condition
eval $patternMatchCode
that evaluates a conditional that was constructed a little earlier.
$userInput =~ /I\b(.+)\byou\./ && $1
It is as if the if block looks like
if ($userInput =~ /I\b(.+)\byou\./ && $1){...}
instead of the way it is written.
If this condition is satisfied, we go into the body of the if block. Inside this if block, we construct a string that is actually a piece of code that has the substitution operator s/// in it followed by an LHS and a RHS. That is, we build a string that looks like the following.
$userInput =~ s/PATTERN/SUBSTITUTION/
The construction is done in parts. First, we obtain the value of the string called $substitutionLeft. The value of $substitutionLeft comes from the pattern matching operation given below.
($substitutionLeft) = ( $lhs =~ m#(/.+)/# );
As a result of this, the actual pattern match portion is extracted from the variable $lhs. Therefore, if the first rule is the relevant rule, the value of $lhs is
/I\b(.+)\byou\./ && $1
and the value of $substitutionLeft is
/I\b(.+)\byou\./
and this value can be used in constructing an s/// string. The s/// string is constructed next using the following statement.
$substitutionCode =
'$userInput =~ ' . 's' . $substitutionLeft . $rhs;
If we are dealing with the first rule, the value of $substitutionCode is a string that looks something like the following.
$userInput =~ s/I\b(.+)\byou\./If you $1 me, I $1 you too\./
This string is evaluated by the Perl expression
eval $substitutionCode;
and this evaluation produces a new value for $userInput as
If you do love me, I do love you too.
assuming the original value of $userInput was
I do love you.
So, we see that the new value of $userInput is actually the output after stripping extra spaces among words, if any.
This process continues for every input that the user types on the terminal. The first rule that is satisfied by pattern matching with the use input is used to produce the system’s output. If several rules can potentially match, only the first is used. So, the ordering of the rules is important. If no rule matches, ELIZA tries to fake by saying
Please go on!
and waiting for the next user input.
The patient-ELIZA interaction continues till the user or the patient types in Bye or a variation of it, at which time ELIZA responds by saying
Thanks!
See you again!
Here, is a complete, but very brief sample interaction with our version of ELIZA. You should increase the number of rules so that you can get more sophisticated conversational behavior.
I am Eliza, a psychiatrist.
Please say something to me.
Say `Bye' to finish.
I love you.
If you love me, I love you too.
I hate you.
If you hate me, I hate you too.
I love you so much.
We love you so much too.
I love your hair.
Your hair is beautiful too. You are simply wonderful!
Please go on!
bye
Thanks!
See you again soon!
