10.3 Some Prolog Revision

There are two Prolog techinques that will be important in the implementation of the recognizer: First, database manipulation, and second, failure driven loops. So, before actually implementing the recognizer, we will briefly explain what you have to know.

10.3.1 Database manipulation

There is one key key decision that we have to make before starting to implement the recognizer and that's how we are going to represent the chart, and how we are going to work with it.

Now, there are various options here. For example, we could represent the chart using some sort of structured list. But there is another, more attractive, way to go: represent the chart using the Prolog database, and manipulate the chart (that is, add new edges) using the database manipulation operations. As we are going to be making heavy use of Prolog's database manipulations, let's quickly run through them and remember how they worked.

There are five database manipulation commands that we will using:

    assert
    retract
    asserta
    assertz
    retractall

How are these used? Suppose we start with an empty database. So if we give the command:

?- listing.
yes

we get a yes --- and the listing (of course) is empty.

Suppose we now give this command:

?- assert(happy(mia)).
yes

It succeeds (the assert/1 commands always succeed). But what is important is not that it succeeds, but the side effect it has on the database, for if we now give the command:

?- listing.
 
happy(mia).
yes

we get again yes --- but now there is something in the database, namely the fact we asserted.

Suppose we then made four more assert commands:

?- assert(happy(vincent)).
yes
 
?- assert(happy(marsellus)).
yes
 
?- assert(happy(butch)).
yes
 
?- assert(happy(vincent)).
yes

and then ask for a listing. Then we get:

?- listing.
 
happy(mia).
happy(vincent).
happy(marsellus).
happy(butch).
happy(vincent).
yes

There is an inverse predicate to assert/1, namely retract/1. For example, if we go straight on and give the command:

?- retract(happy(marsellus)).
yes

and then list the database we get:

?- listing.
 
happy(mia).
happy(vincent).
happy(butch).
happy(vincent).
yes

Suppose we go on further, and say

?- retract(happy(vincent)).
yes

and then ask for a listing:

?- listing.
 
happy(mia).
happy(butch).
happy(vincent).
yes

Note that the first occurrence of happy(vincent) was removed. Prolog removes the first thing in the database that matches the argument of retract.

?- retract(happy(_)).
yes
?- listing.
 
happy(butch).
happy(vincent).
yes

The predicate retractall/1 removes everything that matches its argument:

?- retractall(happy(_)).
yes
?- listing.
yes

If we want more control over where the asserted material is placed, there are two variants of assert, namely:

Prolog puts some restrictions on what can be asserted and retracted. More precisely, other predicates are only allowed to remove or retract clauses of predicates that have been declared dynamic. So, if you want to write a predicate which asserts or retracts clauses of the form happy(mia), you also have to put the following statement into your file:

:- dynamic happy/1.

Database manipulation is useful when we want to store the results of queries, so that if we need to ask the same question in future, we don't need to redo the work --- we just look up the asserted fact. This technique is called `memoization', or `caching'. And of course, this `memoization' idea is the basic concept underlying chart-parsing: we want to store information about the syntactic structure we find, instead of having to re-compute it all the time.

10.3.2 Failure Driven Loops

The idea of failure driven loops is to force Prolog to backtrack until there are no more possibilities left. How can we force Prolog to backtrack? Well, Prolog automatically tries to backtrack when it fails. So, adding a goal which always fails (such as the built in predicate fail/0 which has no effect but to make Prolog fail) at the end of a clause, will force Prolog to backtrack over all the other goals in that clause until it has tried all the possibilities. Here is an example:

write_everybody_happy :- happy(X),
                         write(X),nl,
                         fail.
write_everybody_happy :- true.

If you consult this little program and the ask Prolog the query write_everybody_happy, Prolog will look up in its database all objects that make happy(X) true and will print them out on the screen. So, if the database looked as follows

happy(harry).
happy(ron).
happy(hermione).
happy(hagrid).

Prolog would write on the screen

harry
ron
hermione
hagrid
 
yes


Patrick Blackburn and Kristina Striegnitz
Version 1.2.4 (20020829)