Prolog Database

  • Populating the Database
  • Modifying the Database
  • Keys to the Database
  • Prolog forces one to stretch one's understanding of the terms program and database. A Prolog program is not really a program in the conventional sense because it is not an ordered sequence of instructions for a computer to execute. It is not really a database either because, in addition to declarations of factual information, it contains potentially very complex declarations of the relationships between those facts. For this reason you often see the terms Prolog database and Prolog program used interchangeably.

    When the Prolog runtime responds to a query posed against the Prolog database/program, the behavior can be the same as that from a conventional program, as a simple query triggers another, which triggers another, and so on, solving some large computational problem.

    Understanding that, the term Prolog Database refers to all of the clauses and facts of a Prolog program. These can be dynamically changed during the execution of a Prolog program. Typically, however, to maintain the sanity of the developer, a Prolog program has many predicates that do not change and that do all of the work. The work they do might involve changing another set of predicates. This section describes the tools for dynamically manipulating the Prolog database.

    Clauses in the Prolog database can be in one of two forms:

    We partition the database into these two types of clauses. The database of source clauses we call the dynamic database (comprising dynamic clauses). The database of compiled clauses we call the static database (and its clauses are static clauses).

    If all of your program is interpreted, then all of the clauses are maintained in the dynamic database, and your static database is empty.

    The clauses defining a predicate can be either all dynamic or all static--never mixed.

    Populating

    The predicates consult and reconsult check to see whether the file being loaded is a source file or a compiled file. (They do not use the file extension for this purpose, rather they examine the first few locations of the file. However, if you leave off the extension in the filename, they assume you meant PRO.). Then the correct mechanism is used to load the file.

    The load predicate simply loads a compiled file (.plm).

    consult(FileA), consult([F1, F2, ...]), [F1, F2, ...]

    consult/1 reads a source (.pro) or object (.plm), or list of files. Each file name must be an atom representing the actual file name or path name. If the file exists and can be opened, then Prolog will open it and start reading its contents. If a file name is given with no extension, and there is no corresponding file, then consult/1 assumes the extension was PRO and consults it.

    consult/1 can also be called from a Prolog listener by simply giving a list as a goal. That is, when the listener encounters a goal that is a list, it assumes the list is a list of file names to be consulted.

    Here are some examples of consult.

    consult can, of course be called from your applications as well. For example

    reconsult(FileA), reconsult([F1, F2, ...])

    reconsult/1 is similar to consult/1 except that for the case that the file is a Prolog source file. Then the first time a clause defining predicate P of arity N is read from File then any clauses in the database defining P of arity N which already exist are first retracted. Thus clauses in File completely replace any preexisting clauses in the database which define the same predicate/arity.

    If you are consulting a file for a second time, you usually want to reconsult, because otherwise you will wind up with duplicate clauses in the dynamic database. For example, the built-in edit predicate allows you to edit your source file and then reconsult it, replacing the old version.

    load(FileA), load([F1, F2, ...])

    load/1 is similar to consult, but it only loads object (.plm) files. If no file extension is given, and no files match the name, then it assumes the extension is PLM.

    For example:

    Note, abolish used inconjuction with load makes it possible to have a program dynamically loaded different .plm files that have alternate definitions for certain predicates. You can also use the 'multifile' directive to allow multiple 'load' commands to be used for compiled files with clauses defining the same predicate.

    unload(FileA), unload([F1, F2, ...])

    unload/1allows you to 'unload' all of the clauses that resulted from a 'load' of the same file. This, along with multifile, lets you dynamically change the state of the static database.

    For example, consider a tech support application with a predicate rule/3. If a problem area is determined to be a printer problem, then the file printer_rules.plm can be loaded. Once the problem is resolved, it can be unloaded, clearing the decks for the next problem.

    add, [user]

    The special file name user can be used to indicate that you want to consult clauses entered from the keyboard. You can use this capability from within your program (as opposed to from a listener) by including the goal, consult(user).

    In response to the prompt ?- it is possible to give Prolog a "special" goal, add or [user]. This issues the prompt "|". Now, whenever a clause is entered in response to this prompt, instead of trying to prove it, Prolog will just add it to the database following any current definitions for that predicate. It will then print another | and wait for the next clause to be input. Clauses entered this way must still be terminated with a period.

    To return to top and its ?- prompt, reply to a | prompt with [Ctrl-Z] or give it the clause quit. (which will not be added to the database-rather it just indicates to Prolog that you are through adding goals to the database).

    replace

    replace can be called from the listener and is equivalent to reconsult(user).

    listing, listing(Name), listing(Name/Arity)

    listing/1 prints out all dynamic clauses of Name [/Arity] to the current output file. Name should be bound to the name of a dynamic predicate and, optionally, Arity to the arity of that predicate. Output is paused after each page. Press "n" or "q" to stop the listing at the "More?" prompt.

    listing/0 lists out all dynamic predicates to the current output. Output is paused after each page.

    :- dynamic Name/Arity.

    The dynamic directive is used by the compiler to flag certain predicates as being dynamic rather than compiled. Those predicates will always be 'consulted' rather than loaded, even when the file is compiled.

    Modifying

    A number of predicates are provided for adding and removing static and dynamic clauses.

    abolish(Name/Arity), abolish(Name, Arity)

    abolish removes all clauses (dynamic or compiled) defining the predicate whose name is Name and whose arity is Arity using this predicate. For example:

    abolish removes the definitions of predicates, thus allowing that predicate to be loaded again from a new .PLM file. This feature makes it possible to have a program dynamically loaded different .PLM files that have alternate definitions for certain predicates.

    asserta(Term)

    asserta adds clauses. Term must be sufficiently instantiated to be a term which represents a clause. The clause is added at the front of the database. This predicate fails if the term being asserted is a predicate defined internally by the Prolog system. Such predicates may not be redefined. For example:

    assertz(Term)

    assertz is similar to asserta except the clause is added at the end of the database. Again system predicates may not be redefined. For example:

    assert(Term)

    assert is a synonym for assertz.

    clause(Head, Body)

    clause succeeds if Head can be unified with the head of a dynamic clause in the database, and Body with its body. If clause is backtracked into, it will keep on succeeding as long as there is an untried clause whose head matches Head, in which case it will unify Body with the new body. Eventually the backtracking will fail.

    Head must be sufficiently instantiatedthe name and arity of the structure must be apparent in Head. For example:

    retract(Term)

    retract removes clauses. Term must be sufficiently instantiated to represent a clause. In particular the subterm representing the head of the clause must have a well-defined principal functor and number of arguments. The first clause in the database which matches Term is removed from the database. For example:

    retractall(Term)

    retractall is similar to retract except all clauses which match Term are removed, and it always succeeds. For example:

    Keys

    There is a slightly more general mechanism at work underlying the assertion and retraction of dynamic clauses.

    Terms may be stored in dynamic form by recording them under a Key. A key is an atom and is used to indicate a tag under which terms may be stored. The following predicates record terms under a key.

    db_ref(Head, Body, Dbref)

    db_ref sets/reads the database. If DBref is bound to a database reference then db_ref succeeds if Head and Body can be bound to the head and body of the dynamic clause specified.

    If Ref is unbound and Head and Body are well instantiated enough to specify a dynamic clause, then db_ref unifies Ref with the database reference of the clause.

    The built-in predicate db_ref is used to associate a clause in the database whose head matches Head and whose body matches Body with the database reference DBref.

    This association is bi-directionalgiven a DBref it will find the clause, or, if DBref is a variable, then it binds to the clause whose head matches with Head and whose body matches Body.

    For example:

    In general, database references can only be printed out, unified with themselves or variables, or passed in and out of db_ref.

    erase(DBref)

    erase removes the database entry corresponding to DBref. DBref should be bound to a valid database reference.

    eraseall(Key)

    eraseall/1 erases all database terms recorded under Key.

    instance(DBref, Term)

    instance succeeds if Term can be unified with the Term at DBref. DBref should be bound to a valid database reference.

    recorda(Key, Term, Dbref)

    recorda adds terms to the database. Key should be bound to an atom. Term is added to the database as the first term recorded under Key. The Database Reference for Term is unified with DBref.

    recordz(Key, Term, Dbref)

    recordz also adds terms to the database. Key should be bound to an atom. Term is added to the database as the last term recorded under Key. The Database Reference for Term is unified with DBref.

    record(Key, Term, Dbref)

    record is a synonym for recorda above.

    recorded(Key, Term, Dbref)

    recorded searches for terms in the database. Key must be bound to an atom. Term is unified with the first term it can which was recorded under Key. DBref is unified with the corresponding database reference of the Term. Upon backtracking Term and Dbref are unified successively with subsequent terms/references recorded under Key until exhausted. Then recorded fails.

    Note that, for all the recordx predicates, Term may be any term-even a variable-whereas for assert etc., Term must be in a valid Prolog clause form.

    Copyright ©1987-2000 Amzi! inc. All Rights Reserved.