3
votes

I am studying on Ivan Bratko book: "Programming for Artificial Intelligence" for an universitary exame and using SWI Prolog and I have some doubts about an example show on this book regarding the assert and retract predicates.

It simply present the following code that declare some facts as dynamic:

:-dynamic fast(ann).
:-dynamic slow(tom).
:-dynamic slow(pat).

Then in the Prolog shell use the assert rule to define a new rule into the database:

[debug] 59 ?- assert((faster(X,Y) :- fast(X), slow(Y))).
true.

Ok, so the new rule seems to be added to my database.

Now I try to perform this query and it fail:

[debug] 64 ?- faster(X,Y).
false.

On the book say that the output should be this one:

A = ann
B = tom

and it sound good and rational because I have consult the previous program where say that specify who is fast and who is slow and later I have add the faster rule asserting it...

Why don't work? maybe it depends by the Prolog implementation (SWI-Prolog)?

1
Your use of the dynamic directive should merely indicate the predicate and its number of arguments, e.g. :- dynamic fast/1 and :-dynamic slow/1. Asserting facts for these dynamic predicates is a separate (runtime) step.hardmath
ok, tnx for clarificationAndreaNobili
Interesting sidenote: Things asserted only exist in memory for the duration of the execution of the program. I'm playing around with it, and when I try to retract facts I defined with assertz on separate runs, it fails because there are none to retract. To permanently add to a knowledge base, you need an outputstream with append.G_V

1 Answers

4
votes

The dynamic directive in Prolog is useful in compiled programs (and normally used within a source file to be compiled). If you use assert or an equivalent mechanism to create facts (or rules) in the interactive shell, then SWI-Prolog will already assume those predicates are dynamic.

However the dynamic directive is beneficial in a case where you want to refer to a predicate through a clause in a rule before defining any facts for that predicate. That is, suppose we first do this:

?- assert((faster(X,Y) :- fast(X), slow(Y))).
true.

and then try a query:

?- faster(X,Y).

You might expect this to simply fail, because no facts exist (yet) for fast/1 or slow/1. But actually SWI-Prolog will (by design) throw an error exception:

ERROR: faster/2: Undefined procedure: fast/1

To prevent this we should add the dynamic directives in user entry mode:

?- [user].
|: :-dynamic fast/1, slow/1.
|: (type Ctrl-z to exit user entry mode)
% user://1 compiled 0.00 sec, 1 clauses

Now we will get the expected fail behavior (assuming the previously asserted rule):

?- faster(X,Y).
false.

and you can use the same mode to create your facts:

?- [user].
|: fast(ann).
|: slow(tom).
|: slow(pat).
|: (type Ctrl-z to exit user entry mode)
% user://2 compiled 0.00 sec, 4 clauses
true.

Now the faster query succeeds in two different ways:

?- faster(X,Y).
X = ann,
Y = tom ;
X = ann,
Y = pat.