Node:Generic Prolog Programming, Next:Interfacing with Other Languages, 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.
An alternative is to use an include
declaration.
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 424 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.
:-
to determinately select a
matching clause?
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?
It is possible, and sometimes useful, to write programs that unify a variable to a term in which that variable occurs, thus creating a cyclic term. The usual LP theory forbids the creation of cyclic terms, dictating that an occurs-check should be done each time a variable is unified with a term. Unfortunately, an occurs-check would be so expensive as to render Prolog impractical as a programming language. Thus cyclic terms may be created and may cause loops trying to print them.
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.
You can use:
| ?- prolog_flag(version,Version).
plus a bit of trivial parsing to determine the version number.
| ?- X is 20.66 + 8.85. X = 29.509999999999998 ? yes
Floats like 20.66 and 8.85 are represented in the host computer's native
floating-point format (almost universally, in IEEE 754 format). They
are not represented as the precise rational numbers (2066/100) and
(885/100). Rounding errors are bound to pop up whenever you do
floating-point arithmetic, as your query illustrates. The exact same
thing happens in C. The following C program illustrates
the point: the floating-point sum (20.66+8.85) differs from 29.51 in the
least significant bit.
#include <stdio.h> unsigned int intone = 1; double d1 = 20.66; double d2 = 8.85; double d3 = 29.51; main() { double d4 = d1+d2; int mshalf = ((unsigned short *)&intone)[0]; int lshalf = 1-mshalf; printf("20.66 + 8.85 with 15 decimals, and in hex:\n"); printf("%.15f %0x%0x\n", d4, ((long *)&d4)[mshalf], ((long *)&d4)[lshalf]); printf("29.51 with 15 decimals, and in hex:\n"); printf("%.15f %0x%0x\n", d3, ((long *)&d3)[mshalf], ((long *)&d3)[lshalf]); exit(0); }