Built into the POP-11 language is a small number of simple but powerful procedures for manipulating a database of this sort, known collectively as the database package. It is fairly easy to implement similar procedures in LISP or other AI languages. As we saw in our examination of MSBLOCKS, at least three types of operation can be carried out on a database:
Among the procedures provided for the POP-11 database package are the following:
add For adding new entries to the database;present For searching for a given entry in the database;
allpresent For searching for multiple entries in the database;
remove For deleting entries from the database.
Each of these procedures takes one argument, which is the database entry to be added, removed, or searched for. When calling the remove, present, or allpresent procedure, it is possible, and often extremely useful, to use a pattern, rather than a fully specified list, as the argument to the procedure. Examples of this will be given below:
This procedure adds an item to the database. We can use it to store facts about London of interest to tourists:
add([[the science museum] isa [museum]]);
add([[the science museum] underground [south kensington]]);
add([[the science museum] near
[the natural history museum]]);
add([[the natural history museum] isa [museum]]);
Each of these add commands takes a single argument: a list to be added. The print arrow can be used to display the state of the database:
database =>** [[[the natural history museum] isa [museum]] [[the science museum] near [the natural history museum]] [[the science museum] underground [south kensington]] [[the science museum] isa [museum]]]
The items appear in reverse order because each time the procedure is called it inserts the new item at the beginning of whatever is already there. As we have shown, add is a built-in POP-11 procedure, but we can make clearer how it works by showing how it might be defined:
define add(item); [^item ^^database] -> database; enddefine;
The crucial expression to understand here is
[^item ^^database]
.
This is a new list containing the newly added item followed by the contents
of the old
database.
The new list is then made to be the new value of database, `overwriting' the
old value.
The procedure present searches for an item in the database. It can take either a list or a pattern as argument and it does not alter the database, but simply returns the result <true> if the item is present in the database, or <false> otherwise:
present([[the science museum] isa [museum]])=>
** <true>
present can be given a pattern as argument. So the call
vars x;
present([?x isa [museum]])=>
will return the value
** <true>
Repeated calls to present will match the same item (because a call to present does not alter the database).
The ability of present to work with patterns as well as explicit lists makes it useful for finding items which cannot be completely specified. Also, using present with a pattern as argument has the side-effect of assigning the matched parts of the database item to the pattern variables. So, if we ask for the value of x to be printed out after a call of
present([?x isa [museum]]);
this will be the result:
x=>
** [the natural history museum]
The first item in the database that matches the pattern is used for the assignment. In this call to present the variable x is assigned the value [the natural history museum].
The procedure allpresent takes a list of lists or patterns as input and tries to find a consistent way of matching them against items in the database. It returns <true> if all the patterns can be matched, and <false> otherwise:
allpresent([[[the science museum] isa [museum]]
[[the science museum] underground
[south kensington]]])=>
** <true>allpresent([[?x isa [museum]]
[?y underground [south kensington]]])=>
** <true>
Assignment to pattern variables is made by the first match of each pattern against an item in the database. So the call of allpresent above will assign [the natural history museum] to x and [the science museum] to y. If the same variable is used more than once, then a match must be found that assigns the same value to all instances of the variable -- for example,
allpresent([[?x isa [museum]]
[?x underground [south kensington]]])=>
** <true>
Both patterns can match items in the database so that the same value is given to x -- in this case [the science museum].
The procedure remove searches through the database to find an appropriate item to remove. The search always starts from the beginning. If by any chance there are two or more occurrences of the same item, then only the first is removed. Like present, remove can be used with a pattern, rather than a fully specified list. It will then delete the first entry it finds which matches the pattern as input.
Given the database created earlier, we could remove
[[the natural history museum] isa [museum]]
as follows:
remove([[the natural history museum] isa [museum]]);
We can also give a pattern as an argument to remove, as follows:
vars x,y;
remove([[the science museum] ?x ?y]);
In this call to remove, the pattern
[[the science museum] ?x ?y]
can match
[[the science museum] near [the natural history museum]]
and
[[the science museum] underground [south kensington]]
and
[[the science museum] isa [museum]]
The procedure remove deletes only one item each time it is used. So the first time we call
remove([[the science museum] ?x ?y]);
only the first of these lists will be removed. If we then repeat exactly the same call, the second of the three lists will be deleted. Table 3.1 shows the effects of each procedure.
Alters Can use Returns <true>
database list pattern or <false> as result add Yes No No
remove Yes Yes No
present No Yes Yes
allpresent No Yes Yes
allpresent