Go to the first, previous, next, last section, table of contents.


Loading Programs

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 tracing of goals that compile in-line are not available in compiled code.

The compiler operates in three different modes, controlled by the "Compilation mode" flag (see prolog_flag/3). The possible states of the flag are:

compactcode
Compilation produces byte-coded abstract instructions. This is the default unless SICStus Prolog has been installed with support for fastcode compilation.
fastcode
Compilation produces native machine instructions. Currently only available for 68K, Sparc and MIPS platforms, but not for Muse. Fastcode runs about 3 times faster than compactcode. This is the default if SICStus Prolog has been installed with support for fastcode compilation.
profiledcode
Compilation produces byte-coded abstract instructions instrumented to produce execution profiling data. See section Execution Profiling. Profiling is not available in Runtime Systems.
debugcode
Compilation produces interpreted code, i.e. compiling is replaced by consulting.

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,4) (see section Term and Goal Expansion) "return" a list of sentences, instead of a single sentence.

Predicates which Load Code

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_program/(1,2) 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 with or without a trailing `.ql') or a list of filenames. For each filename in the list, this predicate will search for a file, with the suffix `.ql' added if not specified. 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 have 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:

  1. If the File is user, compile(user) is performed;
  2. If File cannot be found, not even with a `.pl' or `.ql' extension, an error is signaled;
  3. If an object file is found which has not yet been loaded or which has a modification time more recent than what was recorded for the file when it was previously loaded, the file is loaded;
  4. If a source file is found which has not yet been loaded or which has a modification time more recent than what was recorded for the file when it was previously loaded, the file is compiled;
  5. If both a source file and an object file are found, item 3 or 4 applies depending on which file was modified most recently; in case 4 ensure_loaded/1 does not cause object files to become recompiled.
  6. Otherwise, no action is taken.

Declarations

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.

Multifile Declarations

A declaration

:- multifile PredSpec, ..., PredSpec.

where each PredSpec is a predicate spec, causes the specified predicates to become 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. Hook predicates should always be declared as multifile and dynamic, as this is the convention followed in the library modules.

Multifile declarations must precede any other declarations for the same predicate(s)!

Dynamic Declarations

A declaration

:- dynamic PredSpec, ..., 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.

Volatile Declarations

A declaration

:- volatile PredSpec, ..., PredSpec.

where each PredSpec is a predicate spec, causes the specified predicates to become volatile.

A predicate should be declared as volatile if it refers to data that cannot or should not be saved in a saved state. In most cases a volatile predicate will be dynamic, and it will be used to keep facts about streams or memory references. When a program state is saved at run-time, the clauses of all volatile predicates will be left unsaved. The predicate definitions will be saved though, which means that the predicates will keep all properties, that is volatile and maybe dynamic or multifile, when the saved state is restored.

Block Declarations

The declaration

:- block BlockSpec, ..., 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.

Meta-Predicate Declarations

A declaration

:- meta_predicate MetaPredSpec, ..., 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.

Module Declarations

A declaration

:- module(ModuleName, ExportList[, Options]).

where ExportList 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.

Public Declarations

A declaration

:- public PredSpec, ..., 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.

Mode Declarations

A declaration

:- mode ModeSpec, ..., 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.

Parallel and Sequential Declarations

The following declarations serve for the explicit control of parallelism in the Muse Development System.

:- parallel PredSpec, ..., PredSpec.

enables the clauses of the specified predicates to be run in parallel (this is the default).

:- sequential PredSpec, ..., 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).

Considerations for File-To-File Compilation

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,4) 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. This also holds for meta-predicates called by the source files but defined elsewhere, for module name expansion to work correctly. 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 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.


Go to the first, previous, next, last section, table of contents.