Node:Generic Prolog Programming, Next:Interfacing with other Langauges, Previous:Runtime problems, Up:Top
You need a main file for the module, e.g. main.pl
and several subfiles, e.g. sub1.pl
, sub2.pl
, ...
Lay out the main file as follows:
:- module(ModuleName, ExportList). ... clauses/directives ... :- ensure_loaded(sub1). .. clauses/directives ... :- ensure_loaded(sub2).
The subfiles can contain any clauses and directives, including
ensure_loaded/1
directives, but not module/2
directives.
This can be done by defining user:message_hook/3
appropriately:
| ?- [user:user]. % consulting user... | message_hook(error,_,Lines) :- print_message_lines(user_error,error,Lines), abort. | ^D % consulted user in module user, 0 msec 24 bytes
This will intercept any error message, print the message, and abort:
| ?- [user]. % consulting user... | p p. ! Syntax error ! operator expected after expression ! in line 39 ! p ! <<here>> ! p . % consulted user in module user, 0 msec -16 bytes % Execution aborted
There is support for unfolding predicates at compile time:
user:goal_expansion/3
. For example, assume that
is_ornode(
X)
(is_andnode(
X)
) is true if the
shape (principal functor) of X is or/2
(and/2
). If
you consult the following:
:- multifile user:goal_expansion/3. :- dynamic user:goal_expansion/3. user:goal_expansion(is_ornode(Term), _, Term=or(_,_)). user:goal_expansion(is_andnode(Term), _, Term=and(_,_)). plan_tree( [N|_Rest], _GuidanceNodes, _Indent ) :- is_andnode(N). plan_tree( [N|_Rest], _GuidanceNodes, _Indent ) :- is_ornode(N).
then plan_tree/3
becomes transformed to:
plan_tree([A|_], _, _) :- A=and(_,_). plan_tree([A|_], _, _) :- A=or(_,_).
If you are using fcompile/1
, make sure that the definition of
user:goal_expansion/3
, and anything else that the compiler needs
to know, has been loaded at fcompile time. A common idiom is:
?- ensure_loaded(SetOfFiles), fcompile(SetOfFiles).
Note that fcompile/1
is obsolescent with the introduction of
partial saved states (.po
files).
Note also that plan_tree/3
will not be able to determinately select a
matching clause based on A
, as predicates are indexed on the
shape of the first argument only, which is a list in both
clauses. Achieving indexing on A
is the subject of the next question.
Consider the following clauses, with the above goal expansion:
plan_tree( [N|_Rest], _GuidanceNodes, _Indent ) :- is_andnode(N). plan_tree( [N|_Rest], _GuidanceNodes, _Indent ) :- is_ornode(N).
In SICStus, as in most WAMs, indexing is done on the shape of the first
argument. If all arguments are distinct variables A, B,
C, ..., and the first goal is A
= Term
, indexing will
be done on the shape of Term
.
So to enable indexing on the shape of N
, you must transform the clause
e.g. to:
plan_tree( [N|_Rest], _GuidanceNodes, _Indent ) :- plan_tree_flat( N, _Rest, _GuidanceNodes, _Indent ). plan_tree_flat(N, _Rest, _GuidanceNodes, _Indent ) :- is_andnode(N). plan_tree_flat(N, _Rest, _GuidanceNodes, _Indent ) :- is_ornode(N).
With the above goal expansion, this code will indeed index on N
.
Here's some code that purports to print all the Fibonacci numbers.
The author of the code expected retract/1
to backtrack forever, finding
ever new fibs/2
facts.
print_fibs :- retractall(fib(_)), assert(fibs(1,1)), retract(fibs(F1,F2)), write(F1), nl, F3 is F1+F2, assert(fibs(F2,F3)), fail.
If you run it:
| ?- print_fibs. 1 no
It doesn't work because of the semantics for calls to dynamic predicates in the presence of asserts and retracts. SICStus Prolog complies with the ISO Prolog standard in this respect. Clause 7.5.4 of the standard reads:
Any change in the database that occurs as the result of executing a goal (for example, when the activator of a subgoal is a call ofassertz/1
orretract/1
) shall affect only an activation whose execution begins afterwards. The change shall not affect any activation that is currently being executed.
In the above example, the retract/1
goal is unaffected by the
subsequent assert
, and only succeeds once.
X=[97|X], name(A,X).
loops. Is it a bug?
SICStus Prolog mitigates the problem by its ability to unify, compare
assert, and copy cyclic terms without looping. The
write_term/[2,3]
built-in predicate can optionally handle
cyclic terms. Unification with occurs-check is available as a
built-in predicate. Predicates testing (a)cyclicity are available in a
library package. Other predicates usually do not handle cyclic terms well.