Search                        Top                                  Index
TEACH DATABASE                                 Revised A.Sloman Oct 1987
                                       Updated for use with "!" Oct 1996
                                                        Updated Feb 1999

This TEACH file introduces the Pop-11 database. It assumes that you have
some experience with Pop-11 lists and the Pop-11 matcher, e.g.

                       THE POP-11 DATABASE PACKAGE

         CONTENTS - (Use <ENTER> g to access required sections)

 -- Introduction: storing and using information
 -- The POP-11 database
 -- Prerequisites for this teach file
 -- Why we want a database
 -- The initial value of 'database' is an empty list
 -- Storing some 'facts' about Steve
 -- Storing more 'facts' about other people
 -- The POP-11 system doesn't really know whats in the database
 -- We could define 'add' for ourselves
 -- Teach arrow may be useful to you
 -- There is nothing special to the word 'database'
 -- We can check if things are in the database
 -- Present can take a pattern containing variables
 -- Pattern variables should be declared
 -- A more formal definition of -present-
 -- A example using present in a procedure
 -- Use lookup when you are sure some information can be found
 -- The lookup procedure
 -- Grandmothers
 -- How grannies are found
 -- The procedure maternal_granny produces a result
 -- You could have defined lookup yourself
 -- How to clear the database
 -- How to remove selected items from the database
 -- An example of how to use 'remove'
 -- Remove - like present but not add - can be given query variables
 -- Remove can't remove something that isn't there
 -- Summary of the database procedures
 -- Using flush(<pattern>) to remove many items
 -- Generalising present: foreach ... endforeach
 -- Definitions of procedures like present and remove
 -- Revision questions
 -- Further reading

-- Introduction: storing and using information -------------------------

Intelligent  (and  even  some  unintelligent)  systems  need  to   store
information. Some  kinds of  storage are  implicit, some  explicit.  For
example, in the rules you may have learnt for doing long division  there
is a lot of  implicit information about how  symbols on paper  represent
numbers. Some people think that all  the information in human brains  is
stored implicitly  in  complex  states of  tangled  interconnections  of

Yet it seems that we have, and need, some explicit information, such  as
"Ronald's phone number  is 123456",  "Paris is the  capital of  France",
"oxygen is an element", or "No  student who owes fees to the  University
can graduate". These are "propositional" items, things that can be  said
to be  true or  false. There  are other  kinds of  explicit  information
stores, for example images, maps, 3-D models, family trees. Human beings
use many kinds of such representations, and so can computers.

Giving computers human  abilities either for  practical purposes or  for
the purpose of investigating theories of  mind requires us to find  ways
of storing and using different kinds of information, and using the  same
kind of information in different ways.

This is  a large  and complex  topic. For  example, besides  information
stored explicitly  it is  usually necessary  to use  inference rules  or
inference procedures  to derive  new information.  For instance  a  rule
saying that "higher" is a transitive relation enables you to start  from
two facts like

    "Mary is taller than Joe"     and    "Joe is taller than Fred"

to derive  a third.  So even  an explicit  information store  will  have
implicit information,  which depends  on what  inference procedures  are

Computer scientists have developed  many different ways of  representing
and manipulating information in computers. This teach file  introduces a
subset  of  techniques  that  have  been  found  useful  in   Artificial
Intelligence, though they are similar to techniques than can be  applied
elsewhere. The aim is to introduce the basic ideas and show how they can
be made to work on  a computer, but without  worrying about how to  cope
with the problems of efficiency that arise when the information store is
very large  and  complex:  in  that  case  the  techniques  need  to  be

We introduce the  basic techniques  through a  collection of  procedures
that operate on what is called the POP-11 "database"

-- The POP-11 database ------------------------------------------------

"Database" is a  collective name for  a set  of ideas about  how to  use
lists to store 'propositions',  or 'facts'. This  is often a  convenient
technique to use in programs which build descriptions of 'micro worlds'.

For example if you  wish to store information  about a group of  people,
you can make a list of lists of the form

    [occupation mary doctor]
    [occupation joe janitor]
    [age mary 27]
    [age joe 45]

and so on.  (Other formats  for storing  the same  information are  also
possible). Later you may  want to ask questions  about who is a  doctor,
who are all the people who are doctors aged under 45 and so on.

You may also  wish the computer  to perform actions  concerning all  the
people satisfying some description. The  database package allows you  to
do all this easily, using the following procedures, amongst others:

    ADD which adds a 'fact' to the database
    REMOVE which removes a fact
    PRESENT which checks if a fact is in the database
    LOOKUP which also accesses the database.

-- Prerequisites for this teach file ----------------------------------

Before reading the rest of this  teach file you should be familiar  with
the editor,  marking  a  range, compiling  a  range,  switching  between
different VED  files  and  TEACH  files,  defining  procedures,  testing
procedures by  running  them  in your  'output'  file,  declaring  local
variables in a procedure, and using the POP-11 matcher.

The teach files introducing these ideas are:

    TEACH TRACE  shows how to trace and untrace procedures

If you wish to go deeper, try:


Relevant chapters of the POP-11 Primer (TEACH PRIMER) are

    Chapter 6 - Lists
    Chapter 7 - the POP-11 matcher and the POP-11 database

-- Why we want a database ----------------------------------------------

The reason for  wanting a  'database' package is  to allow  us to  write
programs which have  some pretensions  to being  more intelligent  than,
say, ELIZA. The main problem with ELIZA was that it didn't remember what
it had  been told  (nor,  obviously, use  it  to make  inferences).  The
database package enables a  program to store a  collection of facts  and
retrieve them using the pattern matcher.

The database has many  many uses. It can  be used when writing  planning
programs, game  playing  programs,  vision programs  and  programs  that
understand a  subset  of natural  language.  A  very common  use  is  to
represent a  situation,  or 'micro-world'  by  storing a  collection  of
propositions  about  the  world.  Changes  in  the  world  can  then  be
represented by changes in the database.

(TEACH * RIVER illustrates this sort of use of the database.)

The database is just a list of lists. So the procedures that operate  on
the database are built out of procedures that procedures that operate on
lists of lists, adding lists,  removing lists, searching for lists  that
match a pattern, and so on.

-- The initial value of 'database' is an empty list --------------------

We  are  assuming  that  the  world  can  be  described  by  a  list  of
propositions. This is  disputable, but  often useful. You  can find  out
what is in the database by giving the following command to POP-11  (i.e.
mark and compile it).

    database ==>

You may previously have met the print arrow "=>". The pretty-print arrow
"==>" is good for formatting long lists of lists, though it doesn't make
any difference  with  short lists.  So  we  always use  "==>"  with  the

Initially, the database is empty; that is the variable 'database' has as
its 'value' an empty list.

    database ==>
    ** []

-- Storing some 'facts' about Steve ------------------------------------

Suppose we wanted to store the fact that Steve Hardy (who first designed
the POP-11 database and wrote the first version of this teach file) is a
teacher. We could 'add'  a list which is  like an English sentence,  for

    add([steve is a teacher]);

We could also store that he likes apple pie:

    add([steve likes apple pie]);

Mark and compile those two commands then print out the database with the

    database ==>

it should print out:

    ** [[steve likes apple pie] [steve is a teacher]]

-- Storing more 'facts' about other people -----------------------------

Now try adding some more facts to the database, for example:

    add([aaron is a teacher]);
    add([aaron likes jam tart]);
    add([julie is a teacher]);
    add([julie likes baked haddock]);
    database ==>

If you mark and load that lot, and compare the effect of

    database =>
    database ==>

You'll see the  advantage in  the pretty  print arrow.  Notice that  the
latest items ADDed to the database are the first items printed. I.e. the
items go into the database in the  reverse order. This is because it  is
more efficient to add  something to the  front of a list  to make a  new
list than to chug  all the way  down the list  to the end  to add a  new

-- The POP-11 system doesn't really know whats in the database ---------

Just because one element of the list which is the value of 'database' is

    [steve is a teacher]

does NOT mean that the computer KNOWS that Steve is a teacher, any  more
then ELIZA knows what it is to be unhappy. All that is happening is that
various 'list structures' are being built and modified in the computer's
short term memory. We can 'add' any list to the database, for example:

    add([foo baz]);
    database ==>

Try that. Any list given as argument (i.e. input) to the procedure -add-
simply gets  added  to  the  list  of  lists  stored  as  the  value  of

In what  follows we'll  give some  trivial examples  of the  use of  the
database. If you wish you can invent alternative examples which are more
serious. Try out the facilities using your own examples.

-- We could define 'add' for ourselves ---------------------------------

You could, if you wish, define your own version of 'add'. Create a  file
(called, perhaps 'store.p') with  the following procedure definition  in

    define store(fact);
        [^fact ^^database] -> database

Note that  there is  only ONE  up-arrow before  'fact', but  two  before
'database'. After typing this definition into a file, load and mark  it,
then in your 'output' file test it with a command like:

    store([roberts is a politician]);
    store([roberts cares about people]);
    database ==>

-- Teach arrow may be useful to you ------------------------------------

Let's look a bit more closely at the definition of STORE:

The first line says  we are defining a  procedure called "store"  which,
when it is run, will be given one argument (input) called "fact" (and it
is not going to produce any result):

            define store(fact);

The next line has two parts. The first part:

            [^fact ^^database]

Says: build a list containing:
    the value of the variable fact,
and also
    all the elements in the list which is the value of the variable

The list will be left on 'the stack' when it has been built.

The second part of the line:

        -> database

Says: take what is on the top of the stack and assign it to be the value
of the variable database.

If you are unsure about the  difference between the single up-arrow  and
the double up-arrow then look at TEACH * ARROW.

-- There is nothing special to the word 'database' ---------------------

To summarize, the 'database' is NOT  some special sort of object; it  is
just another POP-11 variable. Its value is a list of lists. We choose to
interpret 'database' as  a collection  of 'facts' -  but POP-11  doesn't
interpret the list at all; as far as POP-11 is concerned, 'database'  is
a list like any other list. We could, if we chose, store the database in
a variable called, say, X32 and use a procedure named YYY to add  things
to the database, thus:

    vars x32 = [];  ;;; declare X32 and initialise it with an empty list

    define yyy(z);
        [^z ^^x32] -> x32;      ;;; add the value of z to the list x32

Functionally, this  is equivalent  to ADD  and STORE.  If you  mark  and
compile those lines you can then test them by marking and compiling  the

    yyy([steve is a teacher]);
    yyy([steve likes apple pie]);
    yyy([julie likes baked haddock]);
    yyy([xxx yyy zzz]);
    x32 ==>

Try that to convince yourself that the  names used are of value ONLY  to
people and are arbitrary symbols chosen for OUR convenience.

-- We can check if things are in the database --------------------------

A database that  can only be  added to is  a bit useless.  We need  some
simple way of testing to see if some item is 'present' in the 'database'
(or 'stored'  in  the 'database'  or  'yyyed'  in the  'x32').  Try  the

    present([steve is a teacher]) =>
    present([steve likes baked haddock]) =>
    present([aaron likes jam tart]) =>

Some of  these  should  produce  the  result  <true>  and  some  <false>
depending on whether the list given as argument to -present- is found in
the database or not.

Pronounce "present" in the way you would say "Fred was present in class"
not in  the  way you  would  say  "I'll present you with a medal".  (The
accent is on the first syllable in the former.)

-- Present can take a pattern containing variables ---------------------

You should already have met the use of 'pattern variables' in connection
with MATCHES (patterns can be used  as the second argument to  MATCHES).
-present- can also be given a pattern as its argument, i.e. a list  with
one or more pattern variables.

    present( ![julie likes ??x] ) =>
    x =>
    present( ![??x likes apple pie] ) =>
    x =>

Note that when there is a variable preceded by "?" or "??" in a pattern
used to search the database, you should put "!" in front of the pattern,
for reasons explained in TEACH * MATCHES

When -present- produces the result TRUE,  the variable "it" can be  used
to find out exactly what it was that matched the pattern:

    it =>
    ** [steve likes apple pie]

-- Pattern variables should be declared -------------------------------

Notice that the first time you use  a word as a pattern variable  POP-11
prints out something like


You should avoid that  by always first declaring  the variables you  are
going to use, e.g. try the following:

    vars person, what;

    present( ![??person likes ??what] ) =>

    person, what =>

Declaring variables before you  use them is  not always essential  since
POP-11 declares them for you. But it is an important indication that you
are thinking clearly. It also saves time by stopping POP-11 searching in
the library to see if the variable is declared there.

Sometimes it is absolutely  essential to declare  a pattern variable  as
"local" to a procedure, to stop it interfering with other procedures, as
you'll discover later.

-- A more formal definition of -present- -------------------------------

The word "present"  is not pronounced  as in "present  arms". It's  like
"who is present here today". I.e. the stress is on the first syllable.

1. -present- is a procedure of one argument and one result.

2. Its  argument  is  a list,  which  may  be a  pattern,  i.e.  a  list
containing pattern elements (see TEACH MATCHES, TEACH MATCHES2).

3. It returns the result TRUE if the the argument matches an item in the
database, and returns the result FALSE otherwise.

4. If there are 'query variables' in the argument given to -present-  it
then if a matching  item is found the  variables will have their  values
set appropriately, as with -matches-.

5. If  a matching  item is  found in  the database,  then that  item  is
assigned to be the value of the variable "it", so that programs can tell
exactly what was found.

-- A example using present in a procedure ------------------------------

-present- returns true or false since  we usually use it between IF  and
THEN. Here is an example of a simple procedure called "scold" using  the

It takes a list as  argument, and uses that  list to construct a  longer
list to give to  -present- and decides what  to do depending on  whether
that list is found in the database:

    define scold(person);
        if present([^^person is at the pub]) then
            [i always knew ^^person was a drunkard] =>
            [i always knew ^^person was to be trusted] =>

Note that the use of "^^person" inside list brackets causes Pop-11 to
create a new list containing the elements of the list held in the
variable person. This new list is given to the procedure present, which
then compares it against items in the database. It stops if it finds one
that matches, and returns TRUE. Otherwise it returns FALSE. That is why
present can be used in a condition, i.e. between "if" and "then".

Mark and load that procedure and then try using it, for example:

    ** [i always knew steve was to be trusted]

Then see what the effect of the following is:

    add([steve is at the pub]);
    database ==>

SCOLD varies its behaviour  depending on what is  in the database.  This
depends essentially on the use  of -present- in the "condition"  between
IF and THEN in the definition of SCOLD. (Compare the use of -matches- in
conditions in TEACH RESPOND).

-- Use lookup when you are sure some information can be found ----------

Sometimes you KNOW there will be a certain sort of item in the database,
i.e. one matching a pattern with a  variable, and all you want to do  is
set the value of the variable. You can then use LOOKUP. E.g.

  lookup( ![freddy likes ??x] );    ;;; use semi-colon, not print arrow
  x =>

E.g. you  know there  is an  entry in  the telephone  directory for  the
University, so if you look it up you are only searching the directory to
find WHAT the number is, not WHETHER  there is one. So if the  directory
were a database, you'd do:

  lookup( ![phone number university ??x] );
  x =>

rather than:

  present( ![phone number university ??x] ) =>

The latter will print out <TRUE>,  telling you there is a phone  number.
But you know that already.

By comparison, lookup doesn't  tell you that there  is one, but it  does
give the variable x the  value of the phone  numbr. Also if there  isn't
one, lookup  will produce  a mishap,  whereas present  just returns  the
result false, which could be useful in a conditional expression.

-- The lookup procedure ------------------------------------------------

lookup is like -present-,  in that it takes  a pattern to match  against
different database items. It searches through the database looking for a
matching item.

However, it doesn't return any result. I.e. it doesn't leave anything on
the stack. If  a suitable item  is found in  the database, i.e.  MATCHES
gives the result TRUE, then this is used as a condition for -lookup-  to
stop searching.

If no  matching item is found  in the database,  then -lookup-  causes a

    lookup( ![??x likes climbing glaciers] );

Roughly, lookup is to   present as -->    is to   matches. The operator
"-->" is defined in TEACH MATCHARROW

-- Grandmothers --------------------------------------------------------

Lookup is useful when you KNOW that  an item is in the DATABASE and  are
only interested in the  values of query variables.  For example, if  you
knew that the database  contained information about everybody's  mother,
then you could write a program to find someone's maternal grandmother,
as follows. Note that because we are here using lookup with pattern
variables, ??temp and ??x, inside a procedure definition, we use the
pattern prefix to convert the pattern, as explained in TEACH MATCHES.

    define maternal_granny(person) -> x;
        lvars temp;
        lookup(! [the mother of ^^person is ??temp]);
        lookup(! [the mother of ^^temp is ??x]);

If you left out the two occurrences of "!" you would have to insert a
"vars" variable declaration for the two pattern variables:

    vars temp, x;

You wouldn't use "lookup" for a procedure called AUNT, since you cannot
be sure that everyone has an aunt.

Put the granny procedure into a test file, e.g. test.p, load it and try
it out, after  first  adding suitable information to the database.

    add([the mother of joe is jane]);
    add([the mother of jane is betty]);

which of the following should give a mishap?

    maternal_granny([joe]) =>
    maternal_granny([jane]) =>

Exercise: try defining a procedure called paternal_granny, then test it
with some examples. It should find paternal grandmothers. Do the same
with maternal and paternal grandfathers.

-- How grannies are found ----------------------------------------------

Let's look at how the procedure works.

    define maternal_granny(person) -> x;    ;;; one input, one result
        lvars temp;
        lookup( ! [the mother of ^^person is ??temp] );
        lookup( ! [the mother of ^^temp is ??x] );

Notice that although lookup doesn't produce a result, the first call  of
lookup, if successful, does give a  value to the  variable TEMP, because
of the use  of "??", which means "set the value of".  That value is
USED by "^^temp" in the  second call of lookup to find a value for the
variable X, i.e.

      lookup( ! [the mother of ^^temp is ??x]);

The value of TEMP  is USED because  of "^^" which  means "use the  value
of". (Or more strictly  "include the elements of  the list which is  the
value of..."). By contrast the value of X is changed, because of "??".

-- The procedure maternal_granny produces a result --------------------

The variable X  is defined  (in the  top line)  to be  an 'output  local
variable' for the procedure maternal_granny, so the value found for X is
left on the stack when maternal_granny has finished.

So LOOKUP, which doesn't  produce a result, is  used to find the  result
which maternal_granny has to produce. I.e. LOOKUP gives X a value, which
is then used as the result. (Look back at the definition, and make  sure
you understand all this.)

-- You could have defined lookup yourself ------------------------------

LOOKUP is defined in  terms of -present-. Here  is a procedure which  is
just like lookup, except that it is called FINDIT.

    define findit(pattern);
        if not(present(pattern)) then
            mishap('FINDIT FAILURE', [^pattern]);

The variables in the pattern will get their values when -present-  calls
MATCHES. If present does  not produce the result  TRUE, then the  mishap
occurs. (The procedure MISHAP, which takes two arguments, a message  and
a list of troublesome objects) is built into POP-11.)

If you wish you can type in and test FINDIT:

    vars likes, x;
    findit( ![??likes apple pie] );
    findit( ![uncle tom lives at ??x] );

-- How to clear the database -------------------------------------------

By now you  may have quite  a big  collection of 'facts'  stored in  the
'database'. You  can 'clear'  the  database simply  by assigning  a  new
value, say an empty list, to it; for example:

    [] -> database;
    database ==>

-- How to remove selected items from the database ----------------------

We now introduce yet  another procedure, called  REMOVE, which (how  did
you guess?)  removes an  item from  the database.  Put some  items  into
database, for example:

    add([mary kisses john]);
    add([john kisses jane]);
    add([steve kisses tarina]);
    database ==>

-- An example of how to use 'remove' -----------------------------------

Now remove some items from the database, for example:

    remove([john kisses jane]);
    database ==>

-- Remove - like present but not add - can be given query variables ----

Notice how REMOVE, like ADD, is a 'silent' procedure - it causes nothing
to be printed. Also it produces no result on the stack. Despite this  it
is not useless, for it changes the value of the variable DATABASE.  That
is, it has a 'side effect'.

REMOVE, like PRESENT (but not ADD) can be given an item containing query
variables although this is less useful than in PRESENT, for example:

    remove( ![steve kisses ??x] );

will REMOVE  a fact  about Steve's  romantic habits  from the  DATABASE.
Note that we need "!" because there is a "??" variable.

Should there be several such facts (heaven forbid) then REMOVE will pick
just one for removal. Either way,  the query variables (in this case  X)
will be set  as appropriate.  (In case your  program needs  to know  who
steve used to kiss before the evidence was removed.)

If remove is used in a procedure definition, it is important to put "!"
before a pattern that contains lvars variables.

    remove( ![steve kisses ??x] );

-- Remove can't remove something that isn't there ----------------------

What do you suppose REMOVE  will do if the item  to be deleted isn't  in
the database to begin with? Try it and see:

    remove([ronald kisses nancy]);

-- Summary of the database procedures ----------------------------------

In summary, the four  main database procedures  are ADD, PRESENT  LOOKUP

ADD adds its argument to the database.

PRESENT produces the result TRUE if,  and only if, its argument  matches
something in the database. If it does, the item is assigned to IT.

LOOKUP produces a mishap if the argument does not match anything in  the
database. If it does match, the matching item is assigned to IT.

REMOVE removes  the  first item  in  the  database found  to  match  its
argument. The item found is assigned to IT

PRESENT and REMOVE  can be given  arguments containing query  variables,
i.e. patterns.

DATABASE is a simple POP-11 variable which has as value a list.

-- Using flush(<pattern>) to remove many items ------------------------

If you want to remove EVERYTHING that matches a pattern, then use the
procedure FLUSH.

    flush([joe ==]);

will remove all database items starting with the word "joe". If there
are no such items, it does nothing. It does not produce a mishap, as
remove would in such a case.

    remove([xxx yyy]);
    ;;; INVOLVING:  [xxx yyy]
    ;;; FILE     :  ...teach/database   LINE NUMBER:  725
    ;;; DOING    :  remove ....

    flush([xxx yyy]);

simply does nothing. Try it.

You can remove every item in the database using

    flush( [==] );

That is equivalent to
    [] -> database;

(provided that your database contains only lists: there should not be
anything else in it.)

-- Generalising present: foreach ... endforeach

The procedure flush generalises remove by removing everything that
matches the pattern.

You might wish to generalise present by doing something with every item
that matches a pattern. You can use the "foreach" syntactic form, to do
this. It defines a loop whose body is executed once every time the
pattern given matches something in the database. E.g.

    foreach ![?x likes ?y] do
        ;;; print out the information in a different way
        [^y is liked by ^x] =>

See TEACH FOREACH for more on this. TEACH FOREVERY defines an even more
powerful construct.

-- Definitions of procedures like present and remove -------------------

    (This section can be ignored on first reading)

For the record,  here are the  definitions of two  procedures which  act
very like PRESENT and  REMOVE. Different names are  used so that if  you
try them out, you'll still be able to use the system defined procedures.
Since an understanding of how PRESENT is defined is not essential to its
use, there is no discussion of these two definitions.

    define check(fact) -> result;
        if database matches [== ^fact ==] then
            true -> result;
            false -> result;

NB the space between "==" and "^" is ESSENTIAL. Otherwise POP-11  thinks
you mean the list to contain the symbol "==^" because 'sign'  characters
join up with each other just as letters do in the word "fact".

In the case  of REMOVE  we need to  replace the  original database  with
everything that  was in  it before  the 'fact'  was removed.  Here  is a
procedure called RETRACT which works roughly like REMOVE.

    define retract(fact);

        ;;; declare the pattern variables
        lvars before, after;
        if database matches ![??before ^fact ??after] then
            [^^before ^^after] -> database;
            mishap([RETRACT FAILURE], [^fact]);

Notice the use of the "??" variables in the line:

      if database matches ! [??before ^fact ??after] then

We can't  use just  "==" as  in CHECK,  because we  want to  know  which
elements came before the fact, and  which came after, in order to  build
the new list (using ^^ ) which is to be the database.

-- Revision questions --------------------------------------------------

What you have read  and done so  far introduces the  basic ideas of  the
POP-11 database. Namely it is a list of lists, which can be conveniently
used as a memory store for a set of facts.

You have met  two procedures  for changing the  database. One  procedure
enlarges the database,  and one  deletes items from  the database.  What
were they called?

What sort of input do they take? Do they produce results (on the stack)?

You have met two procedure for searching the database, one which takes a
pattern and produces  a TRUE  or FALSE result  (on the  stack), and  one
which takes a pattern and returns no result if a matching item is found,
but causes  a  mishap if  no  matching item  is  found. What  are  these
procedures called?

How can you clear the database completely (i.e. make sure nothing is in
it) ?

-- Further reading ----------------------------------------------------

HELP * DATABASE summarises the main database facilities.
HELP * MATCHES  summarises the pattern matcher.

See also Chapter 7 of the Pop-11 primer.

If this teach file is your  first introduction to the database, you  may
find it helpful to pause here and try TEACH * RIVER2.    This introduces
you to a  collection  of  library  procedures  which  use  the  database
to represent a simple world, and changes in the world. It also discusses
alternative ways of representing the same information.  Often choosing a
good way is difficult.

You can then do  TEACH * FOREACH,  to find out  how to write  procedures
which do something to each item in the database matching a pattern.

TEACH * INFECT shows how to define procedures which simulate the  spread
of infection.  This illustrates  the use  of the  database to  represent
spreading effects.

TEACH * DATATHINK shows how to define procedures which make inferences.

TEACH * RIVERCHAT shows how to combine mechanisms which manipulate the
database with a conversational "front end" using a pattern matcher.

The section on "Prerequisites" above, refers to relevant chapters of the
Pop11 Primer.

--- C.all/teach/database --------------------------------------------------
--- Copyright University of Sussex 1987. All rights reserved. ----------

--- $poplocal/local/teach/database
--- Copyright University of Birmingham 1999. All rights reserved. ------