The lab numbering has gone a little bit strange this semester it seems (there was a lab 10 last semester), so I've added the semester number to the post title to avoid confusion.

This week's lab was all about Eliza. In case you don't know who (or what) an Eliza is, Eliza is an early attempt at building a chatbot. It isn't very clever, and relies on keywords to understand what you are saying. It's still used today though - mainly in NPCs in games, as they only have to deal with a very limited situation.

Anyway, let's begin building our very own Eliza. First of all, we need a prompt loop, to repeatedly ask the user for more input:

Here I define eliza/0, which welcomes the user and then jumps into eliza_loop/0, which is the main input loop. The main loop simply writes a prompt, asks for input, echoes the input back, and goes back around all over again. Here's some example output:

eliza.
Hello! My name is eliza.
Eliza > test.
You said test
Eliza > cheese.
You said cheese
Eliza > [1,2,1,2,'testing...'].
You said [1,2,1,2,testing...]
Eliza >

This isn't very useful yet - it just echoes back what we say! Let's make it more complicated:

In the above I've changed the main loop up a bit to call respond/1 instead of blindly looping back around. This lets me write rules like those starting on lines #8 and #12 that do something depending on the user's input. We can get our eliza to say goodbye and exit by not looping back around if the user mentions the words "quit", "exit", or "leave", or say hello when someone tells us their name and loop back around again.

There are also two different ways of detecting keywords in the user's input: a double member/2, or a preset list in the rule definition. Examples:

While detecting the items in a list is fairly straightforward, the double member isn't as obvious. It works by taking advantage of Prolog's backtracking. It provides a choice point for each word in the phrase, and then it loops over each of the keywords that we are searching for. If it finds that the current word isn't equal to any of the keywords that it is searching for, it will fail, backtrack, pick the next word, and try again. Another way of looking at it is that Prolog is trying all possible combinations of the input words and the keywords until it finds a match.

If you are following this post as a guide, at this point you can (and should!) add your own custom phrases to practice the techniques described here. Once you have done that, come back here.

Next up, we will add some 'fallback' phrases to our eliza to use when it doesn't understand what has been said. At the moment, it just fails with an impolite false., which isn't any good at all! To do this, we need a list of fallback phrases:

Next we need to get our eliza to loop through our list of fallback phrases in order. We can do this by making the fact that contains the list of fallback phrase dynamic, and then updating it every time we use one. To make something dynamic, you use the dynamic/1 predicate to tell Prolog that fact is dynamic and not static (this is because Prolog applies some clever optimisations to static things that don't work for dynamic things):

:- dynamic list_of_excuses/1

You can use this to tell Prolog that anything in your Prolog program is dynamic. Just change list_of_excuses to the name of the fact or rule, and change the 1 to the arity of the fact or rule that you want to make dynamic.

Next, we need to add a 'catch all' rule at the bottom of our respond/1 definition:

Several things are happening here. firstly, we retract the list of fallback phrases from Prolog's knowledge database and split it up into the first item in the list, and the rest of the items in the list.

Next we create a new list that contains the phrase that we at the front at the end, and then we put this new list back into Prolog's knowledge database.

Lastly, we output the fallback phrase that was at the beginning of the list (but is now at the end) to the user as our reply, before looping back around again with exliza_loop/1.

With that, we our eliza can respond to phrase containing certain keywords, exit when asked, and reply with a fallback phrase if it doesn't understand what was said. Below I have put a small questions and answers type section containing a few of the problems that I had whilst writing this. I've also included the complete Prolog source code that this post is based on.

Common Problems

I had several problems whilst writing this program. I've included a few of them below.

My eliza fails when it doesn't understand something instead of outputting an error.

I found that I didn't get an error message if I included :- after the retract statement. Removing it made it output the error below which I was then able to solve.

I get this error when writing the fallback phrase bit:

ERROR: No permission to modify static_procedure Name/Arity

I'm certain that I put the dynamic name/arity at the top of my prolog source code, but it doesn't work.

I got this because I forgot the :- before the word dynamic. If you are getting this error, this isthe reason why.

Comments

Leave a comment

Mess with this field at your own risk. It is here to catch spambots, and so altering it could cause anything to happen!

Comment:

?

Commenting FAQ

What are the commenting rules?

Never use your real name.

Do not give away any personal informtion.

Criticism is welcome, but it must be constructive.

No abuse or inappropriate content of any kind will be tolerated.

Do not spam.

Any comments that are seen to not follow these rules will probably be deleted. It may also result in a ban for the offending user such that they are unable to view the site for an arbitrary length of time.

These rules may also be ammended without notice, so please check them often.

How can I format my comments?
Basic markdown can be used to format your comments:

Type this

To get this

Notes

*bold text*

bold text

-

_italics text_

italics text

-

~~deleted text~~

deleted

-

`code text`

code text

Inserts some monospaced code. Eventually syntax highlighting will happen automatically. It is preferred that large blocks of code are linked to using a service such as Pastebin, Github Gists or Ideone.

Inserts a hyperlink. Please use responsibly. [rel=nofollow] is in use and spam will be deleted.

---

Inserts a horizontal line. The previous line must be blank.

All HTML will be escaped with HTML entities such that code in <code> blocks will be visible, and for security reasons.
The maximum number of characters allowed is 2000.
What is my email address used for?

Your email address, should you choose to provide it, is used to send you notifications of replies to your comment(s). It is used to display your Gravatar.

Your email address will be kept securely on the server, and nobody else will be given your email address. You will not receive any spam either.

If you do not wish to recieve emails anymore, please email emails@starbeamrainbowlabs.com and I will prevent emails from being sent to your email address. I will eventually write an automated system to handle this, but for now I will deal with requests manually. I should get back to you within 48 hours. Note that your (gr)avatar will also disappear and be replaced by an identicon.

Built by Starbeamrainbowlabs. Feedback can be sent to feedback at starbeamrainbowlabs dot com. Comments can be made on all blog posts. Some icons from the awesome Open Iconic icon set.