Go to the previous, next section.
Programs can be loaded in three different ways: consulted or compiled from source file, or loaded from object files. The latter is the fastest way of loading programs, but of course requires that the programs have been compiled to object files first. Object files may be handy when developing large applications consisting of many source files, but are not strictly necessary since it is possible to save and restore entire execution states (see section Miscellaneous).
Consulted, or interpreted, predicates are equivalent to, but slower than, compiled ones. Although they use different representations, the two types of predicates can call each other freely.
The SICStus Prolog compiler produces compact and efficient code, running about 8 times faster than consulted code, and requiring much less runtime storage. Compiled Prolog programs are comparable in efficiency with LISP programs for the same task. However, against this, compilation itself takes about twice as long as consulting and some debugging aids, such as tracing, are not applicable to compiled code. Spy-points can be placed on compiled procedures, however.
The compiler operates in three different modes, controlled by the
"Compilation mode" flag (see prolog_flag/3
). The possible
states of the flag are:
The compilation mode can be changed by issuing the directive:
| ?- prolog_flag(compiling, OldValue, NewValue).
A Prolog program consists of a sequence of sentences
(see section Syntax of Sentences as Terms). Commands and queries encountered among the
sentences are executed immediately as they are encountered, unless they
can be interpreted as declarations (see section Declarations), which
affect the treatment of forthcoming clauses. Clauses are loaded as they
are encountered.
A Prolog program may also contain a list of sentences (including the
empty list). This is treated as equivalent to those sentences occurring
in place of the list. This feature makes it possible to have
user:term_expansion/2
(see section Term and Goal Expansion) "return" a list of
sentences, instead of a single sentence.
To consult a program, issue the directive:
| ?- consult(Files).
where Files is either the name of a file (including the file `user') or a list of filenames instructs the processor to read-in the program which is in the files. For example:
| ?- consult([dbase,'extras.pl',user]).
When a directive is read it is immediately executed. Any predicate
defined in the files erases any clauses for that predicate already
present. If the old clauses were loaded from a different file than the
present one, the user will be queried first whether (s)he really wants
the new definition. However, if a multifile
declaration
(see section Declarations) is read and the corresponding predicate exists
and has previously been declared as multifile
, new clauses will
be added to the predicate, rather than replacing the old clauses. If
clauses for some predicate appear in more than one file, the later set
will effectively overwrite the earlier set. The division of the program
into separate files does not imply any module structure--any predicate
can call any other (see section The Module System).
consult/1
, used in conjunction with save/1
and
restore/1
, makes it possible to amend a program without having to
restart from scratch and consult all the files which make up the
program. The consulted file is normally a temporary "patch" file
containing only the amended predicate(s). Note that it is possible to
call consult(user)
and then enter a patch directly on the
terminal (ending with ^D). This is only recommended for small,
tentative patches.
| ?- [File|Files].
This is a shorthand way of consulting a list of files. (The case where there is just one filename in the list was described earlier (see section Reading in Programs).
To compile a program in-core, use the built-in predicate:
| ?- compile(Files).
where Files is specified just as for consult/1
.
The effect of compile/1
is very much like that of
consult/1
, except all new procedures will be stored in compiled
rather than consulted form. However, predicates declared as dynamic
(see below) will be stored in consulted form, even though
compile/1
is used.
To compile a program into an object file, use the built-in predicate:
| ?- fcompile(Files).
where Files is specified just as for consult/1
. For each
filename in the list, the compiler will append the suffix `.pl' to it
and try to locate a source file with that name and compile it to an object
file. The object filename if formed by appending the suffix `.ql' to
the specified name. The internal state of SICStus Prolog is not changed as
result of the compilation. See section Considerations for File-To-File Compilation.
To load a program from a set of object files, use the built-in predicate:
| ?- load(Files).
where Files is either a single object filename (specified without
the trailing `.ql') or a list of filenames. For each filename in
the list, this predicate will first search for a file with the suffix
`.ql' added to the name given as an argument. If this fails it will
look for a file with no extra suffix added. This directive has the same
effect as if the source files had been compiled using compile/1
directly (but see section Considerations for File-To-File Compilation).
Finally, to ensure that some files has been compiled or loaded, use the built-in predicate:
| ?- ensure_loaded(Files).
where Files is either a single filename or a list of filenames, similar to the arguments accepted by the above predicates. The predicate takes the following action for each File in the list of filenames:
user
, compile(user)
is
performed;
ensure_loaded/1
does not cause object files to
become recompiled.
When a program is to be loaded, it is sometimes necessary to tell the system to treat some of the predicates specially. This information is supplied by including declarations about such predicates in the source file, preceding any clauses for the predicates which they concern. A declaration is written just as a command, beginning with `:-'. A declaration is effective from its occurrence through the end of file.
Although declarations that affect more than one predicate may be collapsed into a single declaration, the recommended style is to write the declarations for a predicate immediately before its first clause.
Operator declarations are not declarations proper, but rather commands that modify the global table of syntax operators. Operator declarations are executed as they are encountered while loading programs.
The rest of this section details the available forms of predicate declarations.
A declaration
:- multifile PredSpec, @dots{}, PredSpec.
where each PredSpec is a predicate spec, causes the specified
predicates to be multifile
. This means that if more clauses are
subsequently loaded from other files for the same predicate, then the
new clauses will not replace the old ones, but will be added at the end
instead. As of release 3, multifile declarations are required in all
files from where clauses to a multifile predicate are loaded.
An example when multifile declarations are particularly useful is in defining hook predicates. A hook predicate is a user-defined predicate that somehow alters or customizes the behavior of SICStus Prolog. A number of such hook predicates are described in this manual. Often, an application needs to combine the functionality of several software modules, some of which define clauses for such hook predicates. By simply declaring every hook predicates as multifile, the functionality of the clauses for the hook predicates is automatically combined. If this is not done, the last software module to define clauses for a particular hook predicate will effectively supersede any clauses defined for the same hook predicate in a previous module.
If a file containing clauses for a multifile predicate is reloaded, the old clauses from the same file are removed. The new clauses are added at the end.
If a multifile predicate is loaded from a file with no multifile declaration for it, the predicate is redefined as if it were an ordinary predicate (i.e. the user is asked for confirmation).
Clauses of multifile predicates are (currently) always loaded in interpreted form, even if they were processed by the compiler. If performance is an issue, define the multifile predicates as unit clauses or as clauses with a single goal that just calls an auxiliary compiled predicate to perform any time-critical computation.
If a multifile predicate is declared dynamic in one file, it must also be done so in the other files from where it is loaded.
Multifile declarations must precede any other declarations for the same predicate(s)!
A declaration
:- dynamic PredSpec, @dots{}, PredSpec.
where each PredSpec is a predicate spec, causes the specified predicates to become dynamic, which means that other predicates may inspect and modify them, adding or deleting individual clauses. Dynamic predicates are always stored in consulted form even if a compilation is in progress. This declaration is meaningful even if the file contains no clauses for a specified predicate--the effect is then to define a dynamic predicate with no clauses.
The declaration
:- block BlockSpec, @dots{}, BlockSpec.
where each BlockSpec is a mode spec, specifies conditions for
blocking goals of the predicate referred to by the mode spec (f/3
say). When a goal for f/3
is to be executed, the mode specs are
interpreted as conditions for blocking the goal, and if at least one
condition evaluates to true
, the goal is blocked.
A block condition evaluates to true
iff all arguments specified as
`-' are uninstantiated, in which case the goal is blocked until
at least one of those variables is instantiated. If several conditions
evaluate to true
, the implementation picks one of them and
blocks the goal accordingly.
The recommended style is to write the block declarations in front of the source code of the predicate they refer to. Indeed, they are part of the source code of the predicate, and must precede the first clause. For example, with the definition:
:- block merge(-,?,-), merge(?,-,-). merge([], Y, Y). merge(X, [], X). merge([H|X], [E|Y], [H|Z]) :- H @< E, merge(X, [E|Y], Z). merge([H|X], [E|Y], [E|Z]) :- H @>= E, merge([H|X], Y, Z).
calls to merge/3
having uninstantiated arguments in the first
and third position or in the second and third
position will suspend.
The behavior of blocking goals for a given predicate on uninstantiated arguments cannot be switched off, except by abolishing or redefining the predicate.
Block declarations generalize the "wait declarations" of earlier versions of SICStus Prolog. A declaration `:- wait f/3' in the old syntax corresponds to `:- block f(-,?,?)' in the current syntax. See section Use of Term Expansion for a simple way to extend the system to accept the old syntax.
A declaration
:- meta_predicate MetaPredSpec, @dots{}, MetaPredSpec.
where each MetaPredSpec is a mode spec, informs the compiler that certain arguments of the declared predicates are used for passing goals. To ensure the correct semantics in the context of multiple modules, clauses or directives containing goals for the declared predicates may need to have those arguments module name expanded. See section Module Name Expansion for details.
A declaration
:- module(ModuleName, PublicPredicateList).
where PublicPredicateList is a list of predicate specs, declares that the forthcoming predicates should go into the module named ModuleName and that the predicates listed should be exported. See section Defining Modules for details.
A declaration
:- public PredSpec, @dots{}, PredSpec.
where each PredSpec is a predicate spec, has no effect whatsoever, but is accepted for compatibility reasons. In some Prologs, this declaration is necessary for making compiled predicates visible. In SICStus Prolog, predicate visibility is handled by the module system. See section The Module System.
A declaration
:- mode ModeSpec, @dots{}, ModeSpec.
where each ModeSpec is a mode spec, has no effect whatsoever, but is accepted for compatibility reasons. In some Prologs, this declaration helps reduce the size of the compiled code for a predicate, and may speed up its execution. Unfortunately, writing mode declarations can be error-prone, and since errors in mode declaration do not show up while running the predicates interpretively, new bugs may show up when predicates are compiled. However, mode declarations may be used as a commenting device, as they express the programmer's intention of data flow in predicates.
The following declarations serve for the explicit control of parallelism in the Muse Development System.
:- parallel PredSpec, @dots{}, PredSpec.
enables the clauses of the specified predicates to be run in parallel (this is the default).
:- sequential PredSpec, @dots{}, PredSpec.
prohibits the clauses of the specified predicates from running in parallel.
Universal versions of both declarations also exist:
:- sequential. :- parallel.
This indicates to the compiler that all subsequent predicates in the given file become sequential or parallel, unless specifically declared otherwise. The default is to treat all predicates as parallel. Sequential declarations may be necessary to prevent infinite loops in certain programming constructs, such as failure driven loops. e.g. the loop
program :- initialize, generate_solution(X), process_solution(X), fail_if_not_last(X), !, shut_down.
will generate an unbounded number of suspended branches if
generate_solution/1
is a parallel predicate with an unbounded
number of alternatives and process_solution/1
involves a
synchronized operation.
In some rare cases it might also be useful to prevent "slow down" due to too fine granularity in some predicate call. To find such cases you may use the Must trace tool (see section Must).
When compiling a source file to an object file, remember that clauses
are loaded and directives are executed at run time, not at
compile time. Only predicate declarations are processed at compile
time. For instance, it does not work to include operator declarations
or clauses of user:term_expansion/2
or
user:goal_expansion/3
or any auxiliary predicates that they might
need, and rely on the new transformations to be effective for subsequent
clauses of the same file or subsequent files of the same compilation.
Any directives or clauses that affect the compile-time environment must be loaded prior to compiling source files to object files. If this separation into files is unnatural or inconvenient, one can easily ensure that the compile-time environment is up to date by doing
| ?- ensure_loaded(Files), fcompile(Files).
Since the module name expansion takes place at compile time, the module into which the file is to be loaded must be known when compiling to object files. This is no problem for module files because the module name is picked from the module declaration. When non-module files are compiled, the file name may be prefixed with the module name that is to be used for expansion.
| ?- fcompile(Module:Files).
If an object file is loaded into a different module from which it was compiled for, a warning is issued.
Further on for module name expansion to be correctly performed at file-to-file compilation, all meta-predicates used by the compiled file must be meta-declared in the same file or visible as meta-predicates in the compile-time environment.
Go to the previous, next section.