Node:Top, Next:, Previous:(dir), Up:(dir)

SICStus Prolog

This manual documents SICStus Prolog 3.8, October 1999.

Prolog is a simple but powerful programming language developed at the University of Marseilles, as a practical tool for programming in logic. From a user's point of view the major attraction of the language is ease of programming. Clear, readable, concise programs can be written quickly with few errors.


Node:Intro, Next:, Previous:Top, Up:Top

Introduction

Prolog is a simple but powerful programming language developed at the University of Marseilles [Roussel 75], as a practical tool for programming in logic [Kowalski 74]. From a user's point of view the major attraction of the language is ease of programming. Clear, readable, concise programs can be written quickly with few errors.

For an introduction to programming in Prolog, readers are recommended to consult [Sterling & Shapiro 86]. However, for the benefit of those who do not have access to a copy of this book, and for those who have some prior knowledge of logic programming, a summary of the language is included. For a more general introduction to the field of Logic Programming see [Kowalski 79]. See Prolog Intro.

This manual describes a Prolog system developed at the Swedish Institute of Computer Science. Parts of the system were developed by the project "Industrialization of SICStus Prolog" in collaboration with Ericsson Telecom AB, NobelTech Systems AB, Infologics AB and Televerket. The system consists of a WAM emulator written in C, a library and runtime system written in C and Prolog and an interpreter and a compiler written in Prolog. The Prolog engine is a Warren Abstract Machine (WAM) emulator [Warren 83]. Two modes of compilation are available: in-core i.e. incremental, and file-to-file. When compiled, a predicate will run about 8 times faster and use memory more economically. Implementation details can be found in [Carlsson 90] and in several technical reports available from SICS.

SICStus Prolog follows the mainstream Prolog tradition in terms of syntax and built-in predicates, and is largely compatible with DECsystem-10 Prolog and Quintus Prolog.


Node:Acknowledgments, Next:, Previous:Intro, Up:Top

Acknowledgments

The following people have contributed to the development of SICStus Prolog:

Jonas Almgren, Johan Andersson, Stefan Andersson, Tamás Benkő,
Kent Boortz, Per Brand, Göran Bĺge, Mats Carlsson, Jesper
Eskilson, Lena Flood, György Gyaraki, Seif Haridi, Ralph Haygood,
Christian Holzbaur, Key Hyckenberg, Per Mildner, Hans Nilsson, Mats
Nylén, Greger Ottosson, László Péter,
Dan Sahlin, Rob Scott, Thomas Sjöland, Péter
Szeredi, Johan Widén, and Emil Ĺström.

The Industrialization of SICStus Prolog (1988-1991) was funded by

Ericsson Telecom AB, NobelTech Systems AB, Infologics AB and
Televerket under the National Swedish Information Technology
Program IT4.

The development of release 3 (1991-1995) was funded in part by

Ellemtel Utvecklings AB

This manual is based on DECsystem-10 Prolog User's Manual by

D.L. Bowen, L. Byrd, F.C.N. Pereira,
L.M. Pereira, D.H.D. Warren

See CLPQR, for acknowledgments relevant to the clp(Q,R) constraint solver.

See CLPFD, for acknowledgments relevant to the clp(FD) constraint solver.

UNIX is a trademark of Bell Laboratories. MSDOS and Windows is a trademark of Microsoft Corp. OS/2 is a trademark of IBM Corp.


Node:Notation, Next:, Previous:Acknowledgments, Up:Top

Notational Conventions


Node:Keyboard Characters, Next:, Previous:Notation, Up:Notation

Keyboard Characters

When referring to keyboard characters, printing characters are written thus: a, while control characters are written like this: ^A. Thus ^C is the character you get by holding down the <CTL> key while you type c. Finally, the special control characters carriage-return, line-feed and space are often abbreviated to <RET>, <LFD> and <SPC> respectively.


Node:Mode Spec, Next:, Previous:Keyboard Characters, Up:Notation

Mode Spec

When introducing a built-in predicate, we shall present its usage with a mode spec which has the form name(arg, ..., arg) where each arg denotes how that argument should be instantiated in goals, and has one of the following forms:

:ArgName
This argument should be instantiated to a term denoting a goal or a clause or a predicate name, or which otherwise needs special handling of module prefixes. The argument is subject to module name expansion (see Meta Exp).
+ArgName
This argument should be instantiated to a non-variable term.
-ArgName
This argument should be uninstantiated.
?ArgName
This argument may or may not be instantiated.

Mode specs are not only used in the manual, but are part of the syntax of the language as well. When used in the source code, however, the ArgName part must be omitted. That is, arg must be either :, +, -, or ?.


Node:Development and Runtime Systems, Next:, Previous:Mode Spec, Up:Notation

Development and Runtime Systems

The full Prolog system with top-level, compiler, debugger etc. is known as the development system.

It is possible to link user-written C code with a subset of SICStus Prolog to create runtime systems. When introducing a built-in predicate, any limitations on its use in runtime systems will be mentioned.


Node:Function Prototypes, Next:, Previous:Development and Runtime Systems, Up:Notation

Function Prototypes

Whenever this manual documents a C function as part of SICStus Prolog's foreign language interface, the function prototype will be displayed in ANSI C syntax.


Node:ISO Compliance, Previous:Function Prototypes, Up:Notation

ISO Compliance

SICStus Prolog provides two execution modes: the iso mode, which is fully compliant with the International Standard ISO/IEC 13211-1 (PROLOG: Part 1--General Core), and the sicstus mode, which supports code written in earlier versions of SICStus Prolog. The execution mode can be changed using the Prolog flag language; see State Info. Note, however, that SICStus Prolog does not offer a strictly conforming mode which rejects uses of implementation specific features.

To aid programmers who wish to write standard compliant programs, built-in predicates that are part of the ISO Prolog Standard are annotated with [ISO] in this manual. If such a predicate behaves differently in sicstus mode, an appropriate clarification is given. For the few predicates that have a completely different meaning in the two modes, two separate descriptions are given. The one for the iso mode is annotated with [ISO only], while the sicstus mode version is annotated with [SICStus only].


Node:Glossary, Next:, Previous:Notation, Up:Top

Glossary

abolish
To abolish a predicate is to retract all the predicate's clauses and to remove all information about it from the Prolog system, to make it as if that predicate had never existed.
advice-point
A special case of breakpoint, the advice breakpoint. It is distinguished from spypoints in that it is intended for non-interactive debugging, such as checking of program invariants, collecting information, profiling, etc.
alphanumeric
An alphanumeric character is any of the lowercase characters from a to z, the uppercase characters from A to Z, the numerals from 0 to 9, or underscore (_).
ancestors
An ancestor of a goal is any goal which the system is trying to solve when it calls that goal. The most distant ancestor is the goal which was typed at the top-level prompt.
anonymous
An anonymous variable is one which has no unique name, and whose value is therefore inaccessible. An anonymous variable is denoted by an underscore (_).
argument
See predicate, structure, and arity.
arity
The arity of a structure is its number of arguments. For example, the structure customer(jones,85) has an arity of 2.
atom
A character sequence used to uniquely denote some entity in the problem domain. A number is not an atom. Examples of legal atoms are:
hello   *   :=   '#$%'   'New York'   'don\'t'

See Atoms. Atoms are recognized by the built-in predicate atom/1.

atomic term
Synonym for constant.
backtrace
A collection of information on the control flow of the program, gathered by the debugger. Also the display of this information produced by the debugger. The backtrace includes data on goals that were called but not exited and also on goals that exited nondeterministically.
backtracking
The process of reviewing the goals that have been satisfied and attempting to resatisfy these goals by finding alternative solutions.
binding
The process of assigning a value to a variable; used in unification.
blocked goal
A goal which is suspended because it is not instantiated enough.
body
The body of a clause consists of the part of a Prolog clause following the :- symbol.
breakpoint
A description of certain invocations in the program where the user wants the debugger to stop, or to perform some other actions. A breakpoint is specific if it applies to the calls of a specific predicate, possibly under some conditions, otherwise it is generic. Depending on the intended usage, breakpoints can be classified as debugger breakpoints, also known as spypoints, or advice breakpoints, also called advice-points; see Breakpoints.
buffer
A temporary workspace in Emacs that contains a file being edited.
built-in predicate
A predicate that comes with the system and which does not have to be explicitly loaded before it is used.
callable term
A callable term is either a compound term or an atom. Callable terms are recognized by the built-in predicate callable/1.
character code
An integer which is the numeric representation of a character. SICStus Prolog supports character codes in the range 0..2147483647 (i.e. 2^31-1). However, to be able to input or output character codes larger than 255, one needs to use the appropriate wide character external encoding.
character code set
A subset of the set {0, ..., 2^31-1} that can be handled by the external encoding. SICStus Prolog assumes that the character code set is an extension of the ASCII code set, i.e. it includes codes 0..127, and these codes are interpreted as ASCII characters
character-conversion mapping
SICStus Prolog maintains a character-conversion mapping which is used while reading terms and programs. Initially, the mapping prescribes no character conversions. It can be modified by the built-in predicate char_conversion(In, Out), following which In will be converted to Out. Character coversion can be switched off by the char_conversion Prolog flag.
character-type mapping
A function mapping each element of the character code set to one of the character categories (layout, letter, symbol-char, etc.), required for parsing tokens.
clause
A fact or a rule. A rule comprises a head and a body. A fact consists of a head only, and is equivalent to a rule with the body true.
conjunction
A series of goals connected by the connective "and" (that is, a series of goals whose principal operator is ,).
compactcode
Virtual code representation of compiled code. A reasonable compromise between performance and space requirement. A valid value for the compiling Prolog flag.
compile
To load a program (or a portion thereof) into Prolog through the compiler. Compiled code runs more quickly than interpreted code, but you cannot debug compiled code in as much detail as interpreted code.
compound term
A compound term is a functor together with zero or more arguments. For example, in the term father(X), father/1 is the functor, and X is the first and only argument. The argument to a compound term can be another compound term, as in father(father(X)). Compound terms are recognized by the built-in predicate compound/1.
console-based executable
An executable which inherits the standard streams from the process that invoked it, e.g. a UNIX shell or a DOS-prompt.
constant
An integer (for example: 1, 20, -10), a floating-point number (for example: 12.35), or an atom. Constants are recognized by the built-in predicate atomic/1.
consult
To load a program (or a portion thereof) into Prolog through the interpreter. Interpreted code runs more slowly than compiled code, but you can debug interpreted code in more detail than compiled code.
creep
What the debugger does in trace mode, also known as single-stepping. It goes to the next port of a procedure box and prints the goal, then prompts you for input. See Basic Debug.
cursor
The point on the screen at which typed characters appear. This is usually highlighted by a line or rectangle the size of one space, which may or may not blink.
cut
Written as !. A built-in predicate that succeeds when encountered; if backtracking should later return to the cut, the goal that matched the head of the clause containing the cut fails immediately.
database
The Prolog database comprises all of the clauses which have been loaded or asserted into the Prolog system or which have been asserted, except those clauses which have been retracted or abolished.
database reference
A compound term denoting a unique reference to a dynamic clause.
debug
A mode of program execution in which the debugger stops to print the current goal only at procedures which have spypoints set on them (see leap).
debugcode
Interpreted representation of compiled code. A valid value for the compiling Prolog flag.
declaration
A declaration looks like a directive, but is not executed but conveys information about procedures about to be loaded.
deinit function
A function in a foreign resource which is called prior to unloading the resource.
determinate
A procedure is determinate if it can supply only one answer.
development system
A stand-alone executable with the full programming environment, including top-level, compiler, debugger etc. The default sicstus executable is a development system; new development systems containing pre-linked foreign resources can also be created.
directive
A directive is a goal preceded by the prefix operator :-, whose intuitive meaning is "execute this as a query, but do not print out any variable bindings."
disjunction
A series of goals connected by the connective "or" (that is, a series of goals whose principal operator is ;).
dynamic predicate
A predicate that can be modified while a program is running. A predicate must explicitly be declared to be dynamic or it must be added to the database via one of the assertion predicates.
encoded string
A sequence of bytes representing a sequence of possibly wide character codes, using the UTF-8 encoding.
escape sequence
A sequence of characters beginning with \ inside certain syntactic tokens (see Escape Sequences).
export
A module exports a procedure so that other modules can import it.
external encoding (of wide characters)
A way of encoding sequences of wide characters as sequences of (8-bit) bytes, used in stream input and output.
fact
A clause with no conditions--that is, with an empty body. A fact is a statement that a relationship exists between its arguments. Some examples, with possible interpretations, are:
king(louis, france).   % Louis was king of France.
have_beaks(birds).     % Birds have beaks.
employee(nancy, data_processing, 55000).
                     % Nancy is an employee in the
                     % data processing department.

fastcode
Native code representation of compiled code. The fastest, but also the most space consuming representation. Only available for Sparc platforms. A valid value for the compiling Prolog flag.
filename
An atom or a compound term denoting the name of a file. The rules for mapping such terms to absolute filenames are described in Input Output.
floundered query
A query where all unsolved goals are blocked.
foreign predicate
A predicate that is defined in a language other than Prolog, and explicitly bound to Prolog predicates by the Foreign Language Interface.
foreign resource
A named set of foreign predicates.
functor
The name and arity of a compound term. For example, the compound term foo(a,b) is said to have "the functor foo of arity two", which is generally written foo/2.
garbage collection
The freeing up of space for computation by making the space occupied by terms which are no longer available for use by the Prolog system.
generalized predicate spec
A generalized predicate spec is a term of one of the following forms. It is always interpreted wrt. a given module context:
Name
all predicates called Name no matter what arity, where Name is an atom for a specific name or a variable for all names, or
Name/Arity
the predicate of that name and arity, or
Name/(Low-High)
Name/[Low-High]
the predicates of that name with arity in the range Low-High, or
Name/[Arity,...,Arity]
the predicates of that name with one of the given arities, or
Module:Spec
specifying a particular module Module instead of the default module, where Module is an atom for a specific module or a variable for all modules, or
[Spec,...,Spec]
the set of all predicates covered by the Specs.

glue code
Interface code between the Prolog engine and foreign predicates. Automatically generated by the foreign language interface as part of building a linked foreign resource.
goal
A simple goal is a predicate call. When called, it will either succeed or fail.

A compound goal is a formula consisting of simple goals connected by connectives such as "and" (,) or "or" (;).

A goal typed at the top level is called a query.

ground
A term is ground when it is free of (unbound) variables. Ground terms are recognized by the built-in predicate ground/1.
head
The head of a clause is the single goal which will be satisfied if the conditions in the body (if any) are true; the part of a rule before the :- symbol. The head of a list is the first element of the list.
hook predicate
A hook predicate is a procedure that somehow alters or customizes the behavior of a hookable predicate.
hookable predicate
A hookable predicate is a built-in predicate whose behavior is somehow altered or customized by a hook predicate.
import
Exported procedures in a module can be imported by other modules. Once a procedure has been imported by a module, it can be called, or exported, as if it were defined in that module.

There are two kinds of importation: procedure-importation, in which only specified procedures are imported from a module; and module-importation, in which all the predicates made exported by a module are imported.

indexing
The process of filtering a set of potentially matching clauses of a procedure given a goal. For interpreted and compiled code, indexing is done on the principal functor of the first argument. Indexing is coarse w.r.t. big integers and floats.
init function
A function in a foreign resource which is called upon loading the resource.
initialization
An initialization is a goal that is executed when the file in which the initialization is declared is loaded, or upon reinitialization. A initialization is declared as a directive :- initialization Goal.
instantiation
A variable is instantiated if it is bound to a non-variable term; that is, to an atomic term or a compound term.
internal encoding (of wide characters)
A way of encoding wide character sequences internally within the Prolog system. SICStus Prolog uses a technique known as the UTF-8 encoding for this purpose.
interpret
Load a program or set of clauses into Prolog through the interpreter (also known as consulting). Interpreted code runs more slowly than compiled code, but more extensive facilities are available for debugging interpreted code.
invocation box
Same as procedure box.
leap
What the debugger does in debug mode. The debugger shows only the ports of procedures that have spypoints on them. It then normally prompts you for input, at which time you may leap again to the next spypoint (see trace).
leashing
Determines how frequently the debugger will stop and prompt you for input when you are tracing. A port at which the debugger stops is called a "leashed port".
linked foreign resource
A foreign resource that is ready to be installed in an atomic operation, normally represented as a shared object or DLL.
list
A list is written as a set of zero or more terms between square brackets. If there are no terms in a list, it is said to be empty, and is written as []. In this first set of examples, all members of each list are explicitly stated:
[aa, bb,cc]  [X, Y]  [Name]  [[x, y], z]

In the second set of examples, only the first several members of each list are explicitly stated, while the rest of the list is represented by a variable on the right-hand side of the "rest of" operator, |:

[X | Y]  [a, b, c | Y]  [[x, y] | Rest]

| is also known as the "list constructor." The first element of the list to the left of | is called the head of the list. The rest of the list, including the variable following | (which represents a list of any length), is called the tail of the list.

load
To load a Prolog clause or set of clauses, in source or binary form, from a file or set of files.
meta-call
The process of interpreting a callable term as a goal. This is done e.g. by the built-in predicate call/1.
meta-predicate
A meta-predicate is one which calls one or more of its arguments; more generally, any predicate which needs to assume some module in order to operate is called a meta-predicate. Some arguments of a meta-predicate are subject to module name expansion.
mode spec
A term name(arg, ..., arg) where each arg denotes how that argument should be instantiated in goals. See Mode Spec.
module
A module is a set of procedures in a module-file. Some procedures in a module are exported. The default module is user.
module name expansion
The process by which certain arguments of meta-predicates get prefixed by the source module. See Meta Exp.
module-file
A module-file is a file that is headed with a module declaration of the form"
:- module(ModuleName, ExportedPredList).

which must appear as the first term in the file.

multifile predicate
A predicate whose definition is to be spread over more than one file. Such a predicate must be preceded by an explicit multifile declaration in all files containing clauses for it.
mutable term
A special form of compound term which is subject to destructive assignment. See Modify Term. Mutable terms are recognized by the built-in predicate is_mutable/1.
name clash
A name clash occurs when a module attempts to define or import a procedure that it has already defined or imported.
occurs-check
A test to ensure that binding a variable does not bind it to a term where that variable occurs.
one-char atom
An atom which consists of a single character.
operator
A notational convenience that allows you to express any compound term in a different format. For example, if likes in
| ?- likes(sue, cider).

is declared an infix operator, the query above could be written:

| ?- sue likes cider.

An operator does not have to be associated with a predicate. However, certain built-in predicates are declared as operators. For example,

| ?- =..(X, Y).

can be written as

| ?- X =.. Y.

because =.. has been declared an infix operator.

Those predicates which correspond to built-in operators are written using infix notation in the list of built-in predicates at the beginning of the part that contains the reference pages.

Some built-in operators do not correspond to built-in predicates; for example, arithmetic operators. See Standard Operators for a list of built-in operators.

pair
A compound term K-V. Pairs are used by the built-in predicate keysort/2 and by many library modules.
parent
The parent of the current goal is a goal which, in its attempt to obtain a successful solution to itself, is calling the current goal.
port
One of the five key points of interest in the execution of a Prolog procedure. See Procedure Box for a definition.
pre-linked foreign resource
A linked foreign resource that is linked into a stand-alone executable as part of building the executable.
precedence
A number associated with each Prolog operator, which is used to disambiguate the structure of the term represented by an expression containing a number of operators. Operators of lower precedence are applied before those of higher precedence; the operator with the highest precedence is considered the principal functor of the expression. To disambiguate operators of the same precedence, the associativity type is also necessary. See Operators.
predicate
A functor that specifies some relationship existing in the problem domain. For example, < /2 is a built-in predicate specifying the relationship of one number being less than another. In contrast, the functor + /2 is not (normally used as) a predicate.

A predicate is either built-in or is implemented by a procedure.

predicate spec
A compound term name/arity or module:name/arity denoting a predicate.
procedure
A set of clauses in which the head of each clause has the same predicate. For instance, a group of clauses of the following form:
connects(san_francisco, oakland, bart_train).
connects(san_francisco, fremont, bart_train).
connects(concord, daly_city, bart_train).

is identified as belonging to the procedure connects/3.

procedure box
A way of visualizing the execution of a Prolog procedure, A procedure box is entered and exited via ports.
profiledcode
Virtual code representation of compiled code, instrumented for profiling. A valid value for the compiling Prolog flag.
profiling
The process of gathering execution statistics of parts of the program, essentially counting the times selected program points have been reached.
program
A set of procedures designed to perform a given task.
PO file
A PO (Prolog object) file contains a binary representation of a set of modules, predicates, clauses and directives. They are portable between different platforms, except between 32-bit and 64-bit platforms. They are created by save_files/2, save_modules/2, and save_predicates/2.
QL file
A QL (quick load) file contains an intermediate representation of a compiled source code file. They are portable between different platforms, but less efficient than PO files, and are therefore obsolescent. They are created by fcompile/1.
query
A query is a question put by the user to the Prolog system. A query is written as a goal followed by a full-stop in response to the Prolog system prompt. For example,
| ?- father(edward, ralph).

refers to the predicate father/2. If a query has no variables in it, the system will respond either yes or no. If a query contains variables, the system will try to find values of those variables for which the query is true. For example,

| ?- father(edward, X).
X = ralph

After the system has found one answer, the user can direct the system to look for additional answers to the query by typing ;.

recursion
The process in which a running procedure calls itself, presumably with different arguments and for the purpose of solving some subset of the original problem.
region
The text between the cursor and a previously set mark in an Emacs buffer.
rule
A clause with one or more conditions. For a rule to be true, all of its conditions must also be true. For example,
has_stiff_neck(ralph) :-
   hacker(ralph).

This rule states that if the individual ralph is a hacker, then he must also have a stiff neck. The constant ralph is replaced in

has_stiff_neck(X) :-
   hacker(X).

by the variable X. X unifies with anything, so this rule can be used to prove that any hacker has a stiff neck.

runtime kernel
A shared object or DLL containing the SICStus virtual machine and other runtime support for stand-alone executables.
runtime system
A stand-alone executable with a restricted set of built-in predicates and no top-level. Stand-alone applications containing debugged Prolog code and destined for end-users are typically packaged as runtime systems.
saved-state
A snapshot of the state of Prolog saved in a file by save_program/[1,2].
semantics
The relation between the set of Prolog symbols and their combinations (as Prolog terms and clauses), and their meanings. Compare syntax.
sentence
A clause or directive.
side-effect
A predicate which produces a side-effect is one which has any effect on the "outside world" (the user's terminal, a file, etc.), or which changes the Prolog database.
simple term
A simple term is a constant or a variable. Simple terms are recognized by the built-in predicate simple/1.
source code
The human-readable, as opposed to the machine-executable, representation of a program.
source module
The module which is the context of a file being loaded. For module-files, the source module is named in the file's module declaration. For other files, the source module is inherited from the context.
SP_term_ref
A "handle" object providing an interface from C to Prolog terms.
spypoint
A special case of breakpoint, the debugger breakpoint, intended for interactive debugging. Its simplest form, the plain spypoint instructs the debugger to stop at all ports of all invocations of a specified predicate. Conditional spypoints apply to a single predicate, but are more selective: the user can supply applicability tests and prescribe the actions to be carried out by the debugger. A generic spypoint is like a conditional spypoint, but not restricted to a single predicate. See Breakpoints.
stand-alone executable
A binary program which can be invoked from the operating system, containing the SICStus runtime kernel. A stand-alone executable is a development system (e.g. the default sicstus executable), or a runtime system. Both kinds are created by the spld utility. A stand-alone executable does not itself contain any Prolog code; all Prolog code must be loaded upon startup.
static predicate
A predicate that can be modified only by being reloaded or by being abolished. See dynamic predicate.
stream
An input/output channel. See Input Output.
stream alias
A name assigned to a stream at the time of opening, which can be referred to in I/O predicates. Must be an atom. There are also three predefined aliases for the standard streams: user_input, user_output and user_error.
string
A special syntactic notation which is, by default, equivalent to a list of character codes e.g.
"SICStus"

By setting the Prolog flag double_quotes, the meaning of strings can be changed. With an appropriate setting, a string can be made equivalent to a list of one-char atoms, or to an atom. Strings are not a separate data type.

subterm selector
A list of argument positions selecting a subterm within a term (i.e. the subterm can be reached from the term by successively selecting the argument positions listed in the selector). Example: within the term q, (r, s; t) the subterm s is selected by the selector [2, 1, 2].
syntax
The part of Prolog grammar dealing with the way in which symbols are put together to form legal Prolog terms. Compare semantics.
system encoding (of wide characters)
A way of encoding wide character strings, used or required by the operating system environment.
term
A basic data object in Prolog. A term can be a constant, a variable, or a compound term.
trace
A mode of program execution in which the debugger creeps to the next port and prints the goal.
type-in module
The module which is the context of queries.
unblocked goal
A goal which is not blocked.
unbound
A variable is unbound if it has not yet been instantiated.
unification
The process of matching a goal with the head of a clause during the evaluation of a query, or of matching arbitrary terms with one another during program execution.

The rules governing the unification of terms are:


unit clause
See fact.
UTF-8 encoding
See internal encoding
variable
A logical variable is a name that stands for objects that may or may not be determined at a specific point in a Prolog program. When the object for which the variable stands is determined in the Prolog program, the variable becomes instantiated. A logical variable may be unified with a constant, a compound term, or another variable. Variables become uninstantiated when the procedure they occur in backtracks past the point at which they were instantiated.

Variables may be written as any sequence of alphanumeric characters starting with either a capital letter or _; e.g.

X   Y   Z   Name   Position   _c   _305  One_stop

See Variables.

volatile
Predicate property. The clauses of a volatile predicate are not saved in saved-states.
windowed executable
An executable which pops up its own window when run, and which directs the standard streams to that window.
zip
Same as leap mode, except no debugging information is collected while zipping.


Node:Run Intro, Next:, Previous:Glossary, Up:Top

How to Run Prolog

SICStus Prolog offers the user an interactive programming environment with tools for incrementally building programs, debugging programs by following their executions, and modifying parts of programs without having to start again from scratch.

The text of a Prolog program is normally created in a file or a number of files using one of the standard text editors. The Prolog interpreter can then be instructed to read in programs from these files; this is called consulting the file. Alternatively, the Prolog compiler can be used for compiling the file.


Node:Start, Next:, Previous:Run Intro, Up:Run Intro

Getting Started

Under UNIX, SICStus Prolog is normally started from one of the shells. On other platforms, it is normally started by clicking on an icon. However, it is often convenient to run SICStus Prolog under GNU Emacs instead. A GNU Emacs interface for SICStus Prolog is described later (see Emacs Interface). From a shell, SICStus Prolog is started by typing:

% sicstus [options] [-a argument...]

where flags have the following meaning:


-f
Fast start. Don't read any initialization file (~/.sicstusrc or ~/.sicstus.ini) on startup. If the flag is omitted and this file exists, SICStus Prolog will consult it on startup after running any initializations and printing the version banners.
-i
Forced interactive. Prompt for user input, even if the standard input stream does not appear to be a terminal.
-m
Use malloc()/free() in the memory manager's bottom layer.
-l prolog-file
Ensure that the file prolog-file is loaded on startup. This is done before any initialization file is loaded.
-r saved-state
Restore the saved state saved-state on startup. This is done before any prolog-file or initialization file is loaded.
-a argument...
where the arguments can be retrieved from Prolog by prolog_flag(argv, Args), which will unify Args with argument... represented as a list of atoms.
-B[abspath]
Creates a saved state for a development system. This option is not needed for normal use. If abspath is given, it specifies the absolute pathname for the saved state. NOTE: There must not be a space before the path, or it will be interpreted as a separate option.
-R[abspath]
Equivalent to the -B option, except that it builds a saved state for a runtime system instead.

Under UNIX, a saved state file can be executed directly by typing:

% file argument...

This is equivalent to:

% sicstus -r file [-a argument...]

NOTE: As of release 3.7, saved-states do not store the complete path of the binary sp.exe. Instead, they call the main executable sicstus, which is assumed to be found in the shell's path. If there are several versions of SICStus installed, it is up to the user to make sure that the correct start-script is found.

Notice that the flags are not available when executing saved states--all the command-line arguments are treated as Prolog arguments.

The development system checks that a valid SICStus license exists and responds with a message of identification and the prompt | ?- as soon as it is ready to accept input, thus:

SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
| ?-

At this point the top-level is expecting input of a query. You cannot type in clauses or directives immediately (see Inserting Clauses). While typing in a query, the prompt (on following lines) becomes . That is, the | ?- appears only for the first line of the query, and subsequent lines are indented.


Node:Environment Variables, Previous:Start, Up:Start

Environment Variables

The following environment variables can be set before starting SICStus Prolog. Some of these override the default sizes of certain areas. The sizes are given in bytes, but may be followed by K or M meaning kilobytes or megabytes respectively.

SP_CSETLEN
Selects the sub-code-set lengths when the EUC character set is used. For the details, see WCX Environment Variables.
SP_CTYPE
Selects the appropriate character set standard: The supported values are euc (for EUC), utf8 (for Unicode) and iso_8859_1 (for ISO 8859/1). The latter is the default. For the details, see WCX Environment Variables.
SP_PATH
This environment variable can be used to specify the location of the Runtime Library (corresponding to the third argument to SP_initialize()). See Setting SP_PATH under UNIX, for more information.
TMPDIR
If set, indicates the pathname where temporary files should be created. Defaults to /usr/tmp.
GLOBALSTKSIZE
Governs the initial size of the global stack.
LOCALSTKSIZE
Governs the initial size of the local stack.
CHOICESTKSIZE
Governs the initial size of the choicepoint stack.
TRAILSTKSIZE
Governs the initial size of the trail stack.
PROLOGINITSIZE
Governs the size of Prolog's initial memory allocation.
PROLOGMAXSIZE
Defines a limit on the amount of data space which Prolog will use.
PROLOGINCSIZE
Governs the amount of space Prolog asks the operating system for in any given memory expansion.
PROLOGKEEPSIZE
Governs the size of space Prolog retains after performing some computation. By default, Prolog gets memory from the operating system as the user program executes and returns all free memory back to the operating system when the user program does not need any more. If the programmer knows that her program, once it has grown to a certain size, is likely to need as much memory for future computations, then she can advise Prolog not to return all the free memory back to the operating system by setting this variable. Only memory that is allocated above and beyond PROLOGKEEPSIZE is returned to the OS; the rest will be kept.

Send bug reports to sicstus-support@sics.se. Bugs tend actually to be fixed if they can be isolated, so it is in your interest to report them in such a way that they can be easily reproduced.

The mailing list sicstus-users@sics.se is a moderated mailing list for communication among users and implementors. To [un]subscribe, write to sicstus-users-request@sics.se.


Node:Reading In, Next:, Previous:Start, Up:Run Intro

Reading in Programs

A program is made up of a sequence of clauses and directives. The clauses of a predicate do not have to be immediately consecutive, but remember that their relative order may be important (see Procedural).

To input a program from a file file, just type the filename inside list brackets (followed by . and <RET>), thus:

| ?- [file].

This instructs the interpreter to read in (consult) the program. Note that it may be necessary to enclose the filename file in single quotes to make it a legal Prolog atom; e.g.

| ?- ['myfile.pl'].

| ?- ['/usr/prolog/somefile'].

The specified file is then read in. Clauses in the file are stored so that they can later be interpreted, while any directives are obeyed as they are encountered. When the end of the file is found, the system displays on the standard error stream the time spent. This indicates the completion of the query.

Predicates that expect the name of a Prolog source file as an argument use
absolute_file_name/2 (see Stream Pred) to look up the file. This predicate will first search for a file with the suffix .pl added to the name given as an argument. If this fails it will look for a file with no extra suffix added. There is also support for libraries.

In general, this query can be any list of filenames, such as:

| ?- [myprog,extras,tests].

In this case all three files would be consulted.

The clauses for all the predicates in the consulted files will replace any existing clauses for those predicates, i.e. any such previously existing clauses in the database will be deleted.

Note that consult/1 in SICStus Prolog behaves like reconsult/1 in DEC-10 Prolog.


Node:Inserting Clauses, Next:, Previous:Reading In, Up:Run Intro

Inserting Clauses at the Terminal

Clauses may also be typed in directly at the terminal, although this is only recommended if the clauses will not be needed permanently, and are few in number. To enter clauses at the terminal, you must give the special query:

| ?- [user].
|

and the new prompt | shows that the system is now in a state where it expects input of clauses or directives. To return to top level, type ^D. The system responds thus:

{user consulted, 20 msec 200 bytes}


Node:Queries and Directives, Next:, Previous:Inserting Clauses, Up:Run Intro

Queries and Directives

Queries and directives are ways of directing the system to execute some goal or goals.

In the following, suppose that list membership has been defined by loading the following clauses from a file:

member(X, [X|_]).
member(X, [_|L]) :- member(X, L).

(Notice the use of anonymous variables written _.)


Node:Queries, Next:, Previous:Queries and Directives, Up:Queries and Directives

Queries

The full syntax of a query is ?- followed by a sequence of goals. The top level expects queries. This is signaled by the initial prompt | ?- . Thus a query at top level looks like:

| ?- member(b, [a,b,c]).

Remember that Prolog terms must terminate with a full stop (., possibly followed by layout text), and that therefore Prolog will not execute anything until you have typed the full stop (and then <RET>) at the end of the query.

If the goal(s) specified in a query can be satisfied, and if there are no variables as in this example, then the system answers

yes

and execution of the query terminates.

If variables are included in the query, then the final value of each variable is displayed (except for variables whose names begin with _). Thus the query

| ?- member(X, [a,b,c]).

would be answered by

X = a

At this point the system is waiting for input of either just a <RET> or else a ; followed by <RET>. Simply typing <RET> terminates the query; the system responds with yes. However, typing ; causes the system to backtrack (see Procedural) looking for alternative solutions. If no further solutions can be found it outputs no.

The outcome of some queries is shown below, where a number preceded by _ is a system-generated name for a variable.

| ?- member(X, [tom,dick,harry]).

X = tom ;
X = dick ;
X = harry ;

no
| ?- member(X, [a,b,f(Y,c)]), member(X, [f(b,Z),d]).

X = f(b,c),
Y = b,
Z = c

yes
| ?- member(X, [f(_),g]).

X = f(_A)

yes
| ?-

Directives are like queries except that:

  1. Variable bindings are not displayed if and when the directive succeeds.
  2. You are not given the chance to backtrack through other solutions.


Node:Directives, Previous:Queries, Up:Queries and Directives

Directives

Directives start with the symbol :-. Any required output must be programmed explicitly; e.g. the directive:

:- member(3, [1,2,3]), write(ok).

asks the system to check whether 3 belongs to the list [1,2,3]. Execution of a directive terminates when all the goals in the directive have been successfully executed. Other alternative solutions are not sought. If no solution can be found, the system prints:

{Warning: Goal - goal failed}

as a warning.

The principal use for directives (as opposed to queries) is to allow files to contain directives which call various predicates, but for which you do not want to have the answers printed out. In such cases you only want to call the predicates for their effect, i.e. you don't want terminal interaction in the middle of consulting the file. A useful example would be the use of a directive in a file which consults a whole list of other files, e.g.

:- [ bits, bobs, main, tests, data, junk ].

If a directive like this were contained in the file myprog then typing the following at top-level would be a quick way of reading in your entire program:

| ?- [myprog].

When simply interacting with the top-level, this distinction between queries and directives is not normally very important. At top-level you should just type queries normally. In a file, queries are in fact treated as directives, i.e. if you wish to execute some goals then the directive in the file must be preceded by :- or ?-, otherwise it would be treated as a clause.


Node:Syntax Errors, Next:, Previous:Queries and Directives, Up:Run Intro

Syntax Errors

Syntax errors are detected during reading. Each clause, directive or in general any term read in by the built-in predicate read/1 that fails to comply with syntax requirements is displayed on the standard error stream as soon as it is read, along with its position in the input stream and a mark indicating the point in the string of symbols where the parser has failed to continue analysis, e.g.:

| member(X, X$L).
{SYNTAX ERROR: in line 5 (within 5-6)}
** , or ) expected in arguments **
member ( X , X
** here **
$ L ) .

if $ has not been declared as an infix operator.

Note that any comments in the faulty line are not displayed with the error message. If you are in doubt about which clause was wrong you can use the listing/1 predicate to list all the clauses which were successfully read in, e.g.

| ?- listing(member/2).

NOTE: The built in predicates read/[1,2] normaly raise an exception on syntax errors (see Exception). The behavior is controlled by the flag syntax_errors (see prolog_flag/3).


Node:Undefined Predicates, Next:, Previous:Syntax Errors, Up:Run Intro

Undefined Predicates

There is a difference between predicates that have no definition and predicates that have no clauses. The latter case is meaningful e.g. for dynamic predicates (see Declarations) that clauses are being added to or removed from. There are good reasons for treating calls to undefined predicates as errors, as such calls easily arise from typing errors.

The system can optionally catch calls to predicates that have no definition. First the user defined predicate user:unknown_predicate_handler/3 (see Exception) is called. If undefined or if the call fails the action is governed by the state of the unknown/2 flag which can be:

trace
which causes calls to undefined predicates to be reported and the debugger to be entered at the earliest opportunity.
error
which causes calls to such predicates to raise an exception (the default state). See Exception.
warning
which causes calls to such predicates to display a warning message and then fail.
fail
which causes calls to such predicates to fail.

Calls to predicates that have no clauses are not caught.

The built-in predicate unknown(?OldState, ?NewState) unifies OldState with the current state and sets the state to NewState. The built-in predicate debugging/0 prints the value of this state along with its other information. This state is also controlled by the flag unknown (see prolog_flag/3).


Node:Execution, Next:, Previous:Undefined Predicates, Up:Run Intro

Program Execution And Interruption

Execution of a program is started by giving the system a query which contains a call to one of the program's predicates.

Only when execution of one query is complete does the system become ready for another query. However, one may interrupt the normal execution of a query by typing ^C. This ^C interruption has the effect of suspending the execution, and the following message is displayed:

Prolog interruption (h or ? for help) ?

At this point, the development system accepts one-letter commands corresponding to certain actions. To execute an action simply type the corresponding character (lower or upper case) followed by <RET>. The available commands in development systems are:

a
aborts the current computation.
c
continues the execution.
e
exits from SICStus Prolog, closing all files.
h
?
lists available commands.
b
invokes a recursive top-level.
d
z
t
switch on the debugger. See Debug Intro.

If the standard input stream is not connected to the terminal, e.g. by redirecting standard input to a file or a pipe, the above ^C interrupt options are not available. Instead, typing ^C causes SICStus Prolog to exit, and no terminal prompts are printed.


Node:Exiting, Next:, Previous:Execution, Up:Run Intro

Exiting From The Top-Level

To exit from the top-level and return to the shell, either type ^D at the top-level, or call the built-in predicate halt/0, or use the e (exit) command following a ^C interruption.


Node:Nested, Next:, Previous:Exiting, Up:Run Intro

Nested Executions--Break and Abort

The Prolog system provides a way to suspend the execution of your program and to enter a new incarnation of the top level where you can issue queries to solve goals etc. This is achieved by issuing the query (see Execution):

| ?- break.

This invokes a recursive top-level, indicated by the message:

{ Break level 1 }

You can now type queries just as if you were at top-level.

If another call of break/0 is encountered, it moves up to level 2, and so on. To close the break and resume the execution which was suspended, type ^D. The debugger state and current input and output streams will be restored, and execution will be resumed at the predicate call where it had been suspended after printing the message:

{ End break }

Alternatively, the suspended execution can be aborted by calling the built-in predicate abort/0.

A suspended execution can be aborted by issuing the query:

| ?- abort.

within a break. In this case no ^D is needed to close the break; all break levels are discarded and the system returns right back to top-level. I/O streams remain open, but the debugger is switched off. abort/0 may also be called from within a program.


Node:Saving, Next:, Previous:Nested, Up:Run Intro

Saving and Restoring Program States

Once a program has been read, the system will have available all the information necessary for its execution. This information is called a program state.

The state of a program may be saved on disk for future execution. The state consists of all predicates and modules except built-in predicates and clauses of volatile predicates, the current operator declarations, the values of all writable Prolog flags except debugging, source_info, and the user_* stream aliases (see State Info), any blackboard data (see Blackboard Primitives), internal database data (see Database), and profiling data (see Profiling), but no information for source-linked debugging.

To save a program into a file File, type the following query. On UNIX platforms, the file becomes executable:

| ?- save_program(File).

You can also specify a goal to be run when a saved program is restored. This is done by:

| ?- save_program(File, start).

where start/0 is the predicate to be called.

Once a program has been saved into a file File, the following query will restore the system to the saved state:

| ?- restore(File).

If a saved state has been moved or copied to another machine, the path names of foreign resources and other files needed upon restore are typically different at restore time from their save time values. To solve this problem, certain atoms will be relocated during restore as follows:

The purpose of this procedure is to be able to build and deploy an application consisting of a saved state and other files as a directory tree with the saved state at the root: as long as the other files maintain their relative position in the deployed copy, they can still be found upon restore.

NOTE: Foreign resources, see Calling C, are unloaded by save_program/[1,2]. The names and paths of the resources, typically $SP_PATH/library relative, are however included in the saved state. After the save, and after restoring a saved state, this information is used to reload the foreign resources again. The state of the foreign resource in terms of global C variables and allocated memory is thus not preserved. Foreign resources may define init and deinit functions to take special action upon loading and unloading, see Init and Deinit Functions.

As of SICStus Prolog 3.8, partial saved states corresponding to a set of source files, modules, and predicates can be created by the built-in predicates save_files/2, save_modules/2, and save_predicates/2 respectively. These predicates create files in a binary format, by default with the prefix .po (for Prolog object file), which can be loaded by load_files/[1,2]. For example, to compile a program split into several source files into a single object file, type:

| ?- compile(Files), save_files(Files, Object).

For each filename given, the first goal will try to locate a source file with the default suffix .pl and compile it into memory. The second goal will save the program just compiled into an object file whose default suffix is .po. Thus the object file will contain a partial memory image.


Node:Emacs Interface, Previous:Saving, Up:Run Intro

Emacs Interface

This section explains how to use the GNU Emacs interface for SICStus Prolog, and how to customize your GNU Emacs environment for it.

Emacs is a powerful programmable editor especially suitable for program development. It is available for free for many platforms, including various UNIX dialects, Windows and MacOS. For information on obtaining Emacs, see www.emacs.org. For information specific to GNU Emacs or XEmacs, see www.gnu.org and www.xemacs.org respectively.

The advantages of using SICStus in the Emacs environment are source-linked debugging, auto indentation, syntax highlighting, help on predefined predicates (requires the SICStus info files to be installed), loading code from inside Emacs, auto-fill mode, and more.

The Emacs interface is not part of SICStus Prolog proper, but is included in the distribution for convenience. It was written by Emil Ĺström and Milan Zamazal, based on an earlier version of the mode written by Masanobu Umeda. Contributions has also been made by Johan Andersson, Peter Olin, Mats Carlsson, Johan Bevemyr, Stefan Andersson, and Per Danielsson, Henrik Bĺkman, and Tamás Rozmán. Some ideas and also a few lines of code have been borrowed (with permission) from Oz.el by Ralf Scheidhauer and Michael Mehl, the Emacs major mode for the Oz programming language. More ideas and code have been taken from the SICStus debugger mode by Per Mildner.


Node:Installation, Next:, Previous:Emacs Interface, Up:Emacs Interface

Installation

See The Emacs Interface, for more information about installing the Emacs interface.

There are some differences between GNU Emacs and XEmacs. This will be indicated with Emacs-Lisp comments in the examples.

Customizing Emacs

Version 20 of GNU Emacs and XEmacs introduced a new method for editing and storing user settings. This feature is available from the menu bar as Customize and particular Emacs variables can be customized with M-x customize-variable. Using Customize is the preferred way to modify the settings for emacs and the appropriate customize commands will be indicated below, sometimes together with the old method of directly setting Emacs variables.

Enabling Emacs Support for SICStus

Assuming the Emacs interface for SICStus Prolog has been installed in the default location, inserting the following lines in your ~/.emacs will make Emacs use this mode automatically when editing files with a .pl extension:

(setq load-path
   (cons (expand-file-name "/usr/local/lib/sicstus-3.8/emacs")
         load-path))
(autoload 'run-prolog "prolog" "Start a Prolog sub-process." t)
(autoload 'prolog-mode "prolog" "Major mode for editing Prolog programs." t)
(setq prolog-use-sicstus-sd t)
(setq auto-mode-alist (cons '("\\.pl$" . prolog-mode) auto-mode-alist))

where the path in the first line is the file system path to prolog.el (the generic Prolog mode) and sicstus-support.el (SICStus specific code). For example, ~/emacs means that the file is in the user's home directory, in directory emacs. Windows paths can be written like C:/Program Files/SICStus/emacs.

The last line above makes sure that files ending with .pl are assumed to be Prolog files and not Perl, which is the default Emacs setting. If this is undesirable, remove that line. It is then necessary for the user to manually switch to prolog mode by typing M-x prolog-mode after opening a prolog file, for an alternative approach, see Mode Line.

If the shell command sicstus is not available in the default path, then it is necessary to set the value of the environment variable EPROLOG to a shell command to invoke SICStus Prolog. This is an example for C Shell:

setenv EPROLOG /usr/local/bin/sicstus

Enabling Emacs Support for SICStus Documentation

It is possible to look up the documentation for any built in or library predicate from within Emacs (using C-c ? or the menu). For this to work Emacs must be told about the location of the info-files that make up the documentation.

The default location for the info-files are <prefix>/lib/sicstus-3.8/doc/info/ on UNIX platforms and C:/Program Files/SICStus/doc/info/ on Windows.

Add the following to your ~/.emacs file, assuming INFO is the path to the info files, e.g., C:/Program Files/SICStus/doc/info/

(setq Info-default-directory-path
   (append Info-default-directory-path '("INFO")))
for GNU Emacs, or
(setq Info-directory-path
   (append Info-directory-path '("INFO")))

for XEmacs. You can also use M-x customize-group <RET> info <RET> if your Emacs is new enough. You may have to quit and restart Emacs for these changes to take effect.


Node:Basic Configuration, Next:, Previous:Installation, Up:Emacs Interface

Basic Configuration

If the following lines are not present in ~/.emacs, we suggest they are added, so that the font-lock mode (syntax coloring support) is enabled for all major modes in Emacs that support it.

(global-font-lock-mode t)       ; GNU Emacs
(setq font-lock-auto-fontify t) ; XEmacs
(setq font-lock-maximum-decoration t)

These settings and more are also available through M-x customize-group <RET> font-lock.

If one wants to add font-locking only to the prolog mode, the two lines above could be replaced by:

(add-hook 'prolog-mode-hook 'turn-on-font-lock)

Similarly, to turn it off only for prolog mode use:

(add-hook 'prolog-mode-hook 'turn-off-font-lock)


Node:Usage, Next:, Previous:Basic Configuration, Up:Emacs Interface

Usage

A prolog process can be started by choosing Run Prolog from the Prolog menu, by typing C-c <RET>, or by typing M-x run-prolog. It is however not strictly necessary to start a prolog process manually since it is automatically done when consulting or compiling, if needed. The process can be restarted (i.e. the old one is killed and a new one is created) by typing C-u C-c <RET>.

Programs are run and debugged in the normal way, with terminal I/O via the *prolog* buffer. The most common debugging predicates are available from the menu or via key-bindings.

A particularly useful feature under the Emacs interface is source-linked debugging. This is enabled or disabled using the Prolog/Source level debugging menu entry. It can also be enabled by setting the Emacs variable prolog-use-sicstus-sd to t in ~/.emacs. Both these methods set the Prolog flag source_info to emacs. Its value should be emacs while loading the code to be debugged and while debugging. If so, the debugger will display the source code location of the current goal when it prompts for a debugger command, by overlaying the beginning of the current line of code with an arrow. If source_info was off when the code was loaded, or if it was asserted or loaded from user, the current goal will still be shown but out of context.

Note that if the code has been modified since it was last loaded, Prolog's line number information may be invalid. If this happens, just reload the relevant buffer.

Consultation and compilation is either done via the menu or with the following key-bindings:

C-c C-f
Consult file.
C-c C-b
Consult buffer.
C-c C-r
Consult region.
C-c C-p
Consult predicate.
C-c C-c f
Compile file.
C-c C-c b
Compile buffer.
C-c C-c r
Compile region.
C-c C-c p
Compile predicate.

The boundaries used when consulting and compiling predicates are the first and last clauses of the predicate the cursor is currently in.

Other useful key-bindings are:

M-n
Go to the next clause.
M-p
Go to the previous clause.
M-a
Go to beginning of clause.
M-e
Go to end of clause.
M-C-c
Mark clause.
M-C-a
Go to beginning of predicate.
M-C-e
Go to end of predicate.
M-C-h
Mark predicate.
M-{
Go to the previous paragraph (i.e. empty line).
M-}
Go to the next paragraph (i.e. empty line).
M-h
Mark paragraph.
M-C-n
Go to matching right parenthesis.
M-C-p
Go to matching left parenthesis.
M-;
Creates a comment at comment-column. This comment will always stay at this position when the line is indented, regardless of changes in the text earlier on the line, provided that prolog-align-comments-flag is set to t.
C-c C-t
C-u C-c C-t
Enable and disable tracing, respectively.
C-c C-d
C-u C-c C-d
Enable and disable debugging, respectively.
C-c C-z
C-u C-c C-z
Enable and disable zipping, respectively.
C-x SPC
C-u C-x SPC
Set and remove a line breakpoint. This uses the advanced debugger features introduced in SICStus 3.8, Breakpoints.
C-c C-s
Insert the PredSpec of the current predicate into the code.
C-c C-n
Insert the name of the current predicate into the code. This can be useful when writing recursive predicates or predicates with several clauses. See also the prolog-electric-dot-flag variable below.
C-c C-v a
Convert all variables in a region to anonymous variables. This can also be done using the Prolog/Transform/All variables to '_' menu entry. See also the prolog-electric-underscore-flag Emacs variable.
C-c ?
Help on predicate. This requires the SICStus info files to be installed. If the SICStus info files are installed in a nonstandard way, you may have to change the Emacs variable prolog-info-predicate-index.


Node:Mode Line, Next:, Previous:Usage, Up:Emacs Interface

Mode Line

If working with an application split into several modules, it is often useful to let files begin with a "mode line":

%%% -*- Mode: Prolog; Module: ModuleName; -*-

The Emacs interface will look for the mode line and notify the SICStus Prolog module system that code fragments being incrementally reconsulted or recompiled should be imported into the module ModuleName. If the mode line is missing, the code fragment will be imported into the type-in module. An additional benefit of the mode line is that it tells Emacs that the file contains Prolog code, regardless of the setting of the Emacs variable auto-mode-alist. A mode line can be inserted by choosing Insert/Module modeline in the Prolog menu.


Node:Configuration, Next:, Previous:Mode Line, Up:Emacs Interface

Configuration

The behavior of the Emacs interface can be controlled by a set of user-configurable settings. Some of these can be changed on the fly, while some require Emacs to be restarted. To set a variable on the fly, type M-x set-variable <RET> VariableName <RET> Value <RET>. Note that variable names can be completed by typing a few characters and then pressing <TAB>.

To set a variable so that the setting is used every time Emacs is started, add lines of the following format to ~/.emacs:

(setq VariableName Value)

Note that the Emacs interface is presently not using the Customize functionality to edit the settings.

The available settings are:

prolog-system
The Prolog system to use. Defaults to 'sicstus, which will be assumed for the rest of this chapter. See the on-line documentation for the meaning of other settings. For other settings of prolog-system the variables below named sicstus-something will not be used, in some cases corresponding functionality is available through variables named prolog-something.
sicstus-version
The version of SICStus that is used. Defaults to '(3 . 8). Note that the spaces are significant!
prolog-use-sicstus-sd
Set to t (the default) to enable the source-linked debugging extensions by default. The debugging can be enabled via the Prolog menu even if this variable is nil. Note that the source-linked debugging only works if sicstus-version is set correctly.
pltrace-port-arrow-assoc [Obsolescent]
Only relevant for source-linked debugging, this controls how the various ports of invocation boxes (see Procedure Box) map to arrows that point into the current line of code in source code buffers. Initialized as:
'(("call" . ">>>") ("exit" . "+++") ("ndexit" . "?++")
  ("redo" . "<<<") ("fail" . "---") ("exception" . "==>"))

where ndexit is the non-determinate variant of the Exit port. Do not rely on this variable. It will change in future releases.

prolog-indent-width
How many positions to indent the body of a clause. Defaults to tab-width, normally 8.
prolog-paren-indent
The number of positions to indent code inside grouping parentheses. Defaults to 4, which gives the following indentation.
p :-
        (   q1
        ;   q2,
            q3
        ).

Note that the spaces between the parentheses and the code are automatically inserted when <TAB> is pressed at those positions.

prolog-align-comments-flag
Set to nil to prevent single %-comments to be automatically aligned. Defaults to t.

Note that comments with one % are indented to comment-column, comments with two % to the code level, and that comments with three % are never changed when indenting.

prolog-indent-mline-comments-flag
Set to nil to prevent indentation of text inside /* ... */ comments. Defaults t.
prolog-object-end-to-0-flag
Set to nil to indent the closing } of an object definition to prolog-indent-width. Defaults to t.
sicstus-keywords
This is a list with keywords that are highlighted in a special color when used as directives (i.e. as :- keyword). Defaults to
'((sicstus
     ("block" "discontiguous" "dynamic" "initialization"
      "meta_predicate" "mode" "module" "multifile" "public" "volatile"))))

prolog-electric-newline-flag
Set to nil to prevent Emacs from automatically indenting the next line when pressing <RET>. Defaults to t.
prolog-hungry-delete-key-flag
Set to t to enable deletion of all white space before the cursor when pressing the delete key (unless inside a comment, string, or quoted atom). Defaults to nil.
prolog-electric-dot-flag
Set to t to enable the electric dot function. If enabled, pressing . at the end of a non-empty line inserts a dot and a newline. When pressed at the beginning of a line, a new head of the last predicate is inserted. When pressed at the end of a line with only whitespace, a recursive call to the current predicate is inserted. The function respects the arity of the predicate and inserts parentheses and the correct number of commas for separation of the arguments. Defaults to nil.
prolog-electric-underscore-flag
Set to t to enable the electric underscore function. When enabled, pressing underscore (_) when the cursor is on a variable, replaces the variable with the anynomous variable. Defaults to nil.
prolog-old-sicstus-keys-flag
Set to t to enable the key-bindings of the old Emacs interface. These bindings are not used by default since they violate GNU Emacs recommendations. Defaults to nil.
prolog-use-prolog-tokenizer-flag
Set to nil to use built-in functions of Emacs for parsing the source code when indenting. This is faster than the default but does not handle some of the syntax peculiarities of Prolog. Defaults to t.
prolog-parse-mode
What position the parsing is done from when indenting code. Two possible settings: 'beg-of-line and 'beg-of-clause. The first is faster but may result in erroneous indentation in /* ... */ comments. The default is 'beg-of-line.
prolog-imenu-flag
Set to t to enable a new Predicate menu which contains all predicates of the current file. Choosing an entry in the menu moves the cursor to the start of that predicate. Defaults to nil.
prolog-info-predicate-index
The info node for the SICStus predicate index. This is important if the online help function is to be used (by pressing C-c ?, or choosing the Prolog/Help on predicate menu entry). The default setting is "(sicstus)Predicate Index".
prolog-underscore-wordchar-flag
Set to nil to not make underscore (_) a word-constituent character. Defaults to t.


Node:Tips, Previous:Configuration, Up:Emacs Interface

Tips

Some general tips and tricks for using the SICStus mode and Emacs in general are given here. Some of the methods may not work in all versions of Emacs.


Node:Font-locking, Next:, Previous:Tips, Up:Tips

Font-locking

When editing large files, it might happen that font-locking is not done because the file is too large. Typing M-x lazy-lock-mode results in only the visible parts of the buffer being highlighted, which is much faster, see its Emacs on-line documentation for details.

If the font-locking seems to be incorrect, choose Fontify Buffer from the Prolog menu.


Node:Auto-fill mode, Next:, Previous:Font-locking, Up:Tips

Auto-fill mode

Auto-fill mode is enabled by typing M-x auto-fill-mode. This enables automatic line breaking with some features. For example, the following multiline comment was created by typing M-; followed by the text. The second line was indented and a % was added automatically.

dynamics([]).       % A list of pit furnace
                    % dynamic instances


Node:Speed, Next:, Previous:Auto-fill mode, Up:Tips

Speed

There are several things to do if the speed of the Emacs environment is a problem:


Node:Changing colors, Previous:Speed, Up:Tips

Changing Colors

The prolog mode uses the default Emacs colors for font-locking as far as possible. The only custom settings are in the prolog process buffer. The default settings of the colors may not agree with your preferences, so here is how to change them.

If your emacs support it, use Customize, M-x customize-group <RET> font-lock <RET> will show the Customize settings for font locking and also contains pointers to the Customize group for the font lock (type)faces. The rest of this section outlines the more involved methods needed in older versions of Emacs.

First of all, list all available faces (a face is a combined setting of foreground and background colors, font, boldness, etc.) by typing M-x list-faces-display.

There are several functions that change the appearance of a face, the ones you will most likely need are:

set-face-foreground
set-face-background
set-face-underline-p
make-face-bold
make-face-bold-italic
make-face-italic
make-face-unbold
make-face-unitalic

These can be tested interactively by typing M-x function-name. You will then be asked for the name of the face to change and a value. If the buffers are not updated according to the new settings, then refontify the buffer using the Fontify Buffer menu entry in the Prolog menu.

Colors are specified by a name or by RGB values. Available color names can be listed with M-x list-colors-display.

To store the settings of the faces, a few lines must be added to ~/.emacs. For example:

;; Customize font-lock faces
(add-hook 'font-lock-mode-hook
          '(lambda ()
             (set-face-foreground font-lock-variable-name-face "#00a000")
             (make-face-bold font-lock-keyword-face)
             (set-face-foreground font-lock-reference-face "Blue")
             ))


Node:Prolog Intro, Next:, Previous:Run Intro, Up:Top

The Prolog Language

This chapter provides a brief introduction to the syntax and semantics of a certain subset of logic (definite clauses, also known as Horn clauses), and indicates how this subset forms the basis of Prolog.


Node:Syntax, Next:, Previous:Prolog Intro, Up:Prolog Intro

Syntax, Terminology and Informal Semantics


Node:Terms, Next:, Previous:Syntax, Up:Syntax

Terms

The data objects of the language are called terms. A term is either a constant, a variable or a compound term.


Node:Integers, Next:, Previous:Terms, Up:Terms

Integers

The constants include integers such as

0   1   999   -512

Besides the usual decimal, or base 10, notation, integers may also be written in other base notations. In sicstus mode, any base from 2 to 36 can be specified, while in iso mode bases 2 (binary), 8 (octal), and 16 (hex) can be used. Letters A through Z (upper or lower case) are used for bases greater than 10. E.g.

15   2'1111   8'17  16'f  % sicstus mode
15   0b1111   0o17  0xf   % iso mode

all represent the integer fifteen. Except for the first, decimal, notation, the forms in the first line are only acceptable in sicstus mode, while those in the second line are only valid in iso mode.

There is also a special notation for character constants. E.g.

0'A   0'\x41   0'\101

are all equivalent to 65 (the character code for A). 0' followed by any character except \ (backslash) is thus read as an integer. If 0' is followed by \, the \ denotes the start of an escape sequence with special meaning (see Escape Sequences).


Node:Floats, Next:, Previous:Integers, Up:Terms

Floats

Constants also include floats such as

1.0   -3.141   4.5E7   -0.12e+8   12.0e-9

Note that there must be a decimal point in floats written with an exponent, and that there must be at least one digit before and after the decimal point.


Node:Atoms, Next:, Previous:Floats, Up:Terms

Atoms

Constants also include atoms such as

a   void   =   :=   'Algol-68'   []

Atoms are definite elementary objects, and correspond to proper nouns in natural language. For reference purposes, here is a list of the possible forms which an atom may take:

  1. Any sequence of alphanumeric characters (including _), starting with a lower case letter.
  2. Any sequence from the following set of characters:
    +-*/\^<>=~:.?@#$&
    This set can in fact be larger; see Token String for a precise definition.
  3. Any sequence of characters delimited by single quotes. If the single quote character is included in the sequence it must be escaped, e.g. 'can\'t'. Backslashes in the sequence denote escape sequences (see Escape Sequences).
  4. Any of: ! ; [] {}
    Note that the bracket pairs are special: [] and {} are atoms but [, ], {, and } are not. However, when they are used as functors (see below) the form {X} is allowed as an alternative to {}(X). The form [X] is the normal notation for lists, as an alternative to .(X,[]).


Node:Variables, Next:, Previous:Atoms, Up:Terms

Variables

Variables may be written as any sequence of alphanumeric characters (including _) starting with either a capital letter or _; e.g.

X   Value   A   A1   _3   _RESULT

If a variable is only referred to once in a clause, it does not need to be named and may be written as an anonymous variable, indicated by the underline character _. A clause may contain several anonymous variables; they are all read and treated as distinct variables.

A variable should be thought of as standing for some definite but unidentified object. This is analogous to the use of a pronoun in natural language. Note that a variable is not simply a writable storage location as in most programming languages; rather it is a local name for some data object, cf. the variable of pure LISP and identity declarations in Algol68.


Node:Compound Terms, Previous:Variables, Up:Terms

Compound Terms

The structured data objects of the language are the compound terms. A compound term comprises a functor (called the principal functor of the term) and a sequence of one or more terms called arguments. A functor is characterized by its name, which is an atom, and its arity or number of arguments. For example the compound term whose functor is named point of arity 3, with arguments X, Y and Z, is written

point(X, Y, Z)

Note that an atom is considered to be a functor of arity 0.

Functors are generally analogous to common nouns in natural language. One may think of a functor as a record type and the arguments of a compound term as the fields of a record. Compound terms are usefully pictured as trees. For example, the term

s(np(john),vp(v(likes),np(mary)))

would be pictured as the compound term

       s
     /   \
  np       vp
  |       /  \
john     v     np
         |     |
       likes  mary

Sometimes it is convenient to write certain functors as operators--2-ary functors may be declared as infix operators and 1-ary functors as prefix or postfix operators. Thus it is possible to write, e.g.

X+Y     (P;Q)     X<Y      +X     P;

as optional alternatives to

+(X,Y)   ;(P,Q)   <(X,Y)   +(X)   ;(P)

The use of operators is described fully below (see Operators).

Lists form an important class of data structures in Prolog. They are essentially the same as the lists of LISP: a list either is the atom [] representing the empty list, or is a compound term with functor . and two arguments which are respectively the head and tail of the list. Thus a list of the first three natural numbers is the compound term

  .
 / \
1    .
    / \
   2    .
       / \
      3   []

which could be written, using the standard syntax, as

.(1,.(2,.(3,[])))

but which is normally written, in a special list notation, as

[1,2,3]

The special list notation in the case when the tail of a list is a variable is exemplified by

[X|L]     [a,b|L]

representing

   .               .
  / \             / \
X     L         a     .
                     / \
                   b     L

respectively.

Note that this notation does not add any new power to the language; it simply makes it more readable. e.g. the above examples could equally be written

.(X,L)    .(a,.(b,L))

For convenience, a further notational variant is allowed for lists of integers which correspond to character codes or one-char atoms. Lists written in this notation are called strings. E.g.

"SICStus"

which, by default, represents exactly the same list as

[83,73,67,83,116,117,115]

The Prolog flag double_quotes can be used to change the way strings are interpreted. The default value of the flag is codes, which implies the above interpretation. If the flag is set to chars, a string is transformed to a list of one-char atoms. E.g. with this setting the above string represents the list:

['S','I','C','S',t,u,s]

Finally if double_quotes has the value atom, then the string is made equivalent to the atom formed from its characters: the above sample string is then the same as the atom 'SICStus'.

As for quoted atoms, if a double quote character is included in the sequence it must be escaped, e.g. "can\'t". Backslashes in the sequence denote escape sequences (see Escape Sequences).


Node:Programs, Previous:Terms, Up:Syntax

Programs

A fundamental unit of a logic program is the goal or procedure call. e.g.

gives(tom, apple, teacher)   reverse([1,2,3], L)   X<Y

A goal is merely a special kind of term, distinguished only by the context in which it appears in the program. The (principal) functor of a goal identifies what predicate the goal is for. It corresponds roughly to a verb in natural language, or to a procedure name in a conventional programming language.

A logic program consists simply of a sequence of statements called sentences, which are analogous to sentences of natural language. A sentence comprises a head and a body. The head either consists of a single goal or is empty. The body consists of a sequence of zero or more goals (i.e. it too may be empty). If the head is not empty, the sentence is called a clause.

If the body of a clause is empty, the clause is called a unit clause, and is written in the form

P.

where P is the head goal. We interpret this declaratively as

Goals matching P are true.

and procedurally as

Goals matching P are satisfied.

If the body of a clause is non-empty, the clause is called a rule, and is written in the form

P :- Q, R, S.

where P is the head goal and Q, R and S are the goals which make up the body. We can read such a clause either declaratively as

P is true if Q and R and S are true.

or procedurally as

To satisfy goal P, satisfy goals Q, R and S.

A sentence with an empty head is called a directive (see Directives), and is written in the form

:- P, Q.

where P and Q are the goals of the body. Such a query is read declaratively as

Are P and Q true?

and procedurally as

Satisfy goals P and Q.

Sentences generally contain variables. Note that variables in different sentences are completely independent, even if they have the same name--i.e. the lexical scope of a variable is limited to a single sentence. Each distinct variable in a sentence should be interpreted as standing for an arbitrary entity, or value. To illustrate this, here are some examples of sentences containing variables, with possible declarative and procedural readings:

  1. employed(X) :- employs(Y,X).

    "Any X is employed if any Y employs X."

    "To find whether a person X is employed, find whether any Y employs X."

  2. derivative(X,X,1).

    "For any X, the derivative of X with respect to X is 1."

    "The goal of finding a derivative for the expression X with respect to X itself is satisfied by the result 1."

  3. ?- ungulate(X), aquatic(X).

    "Is it true, for any X, that X is an ungulate and X is aquatic?"

    "Find an X which is both an ungulate and aquatic."

In any program, the predicate for a particular (principal) functor is the sequence of clauses in the program whose head goals have that principal functor. For example, the predicate for a 3-ary functor concatenate/3 might well consist of the two clauses

concatenate([], L, L).
concatenate([X|L1], L2, [X|L3]) :- concatenate(L1, L2, L3).

where concatenate(L1,L2,L3) means "the list L1 concatenated with the list L2 is the list L3". Note that for predicates with clauses corresponding to a base case and a recursive case, the preferred style is to write the base case clause first.

In Prolog, several predicates may have the same name but different arities. Therefore, when it is important to specify a predicate unambiguously, the form name/arity is used; e.g. concatenate/3.

Certain predicates are predefined by built-in predicates supplied by the Prolog system. Such predicates are called built-in predicates.

As we have seen, the goals in the body of a sentence are linked by the operator , which can be interpreted as conjunction ("and"). It is sometimes convenient to use an additional operator ;, standing for disjunction ("or"). (The precedence of ; is such that it dominates , but is dominated by :-.) An example is the clause

grandfather(X, Z) :-
        (mother(X, Y); father(X, Y)),
        father(Y, Z).

which can be read as

For any X, Y and Z, X has Z as a grandfather if either the mother of X is Y or the father of X is Y, and the father of Y is Z.

Such uses of disjunction can always be eliminated by defining an extra predicate--for instance the previous example is equivalent to

grandfather(X,Z) :- parent(X,Y), father(Y,Z).

parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).

--and so disjunction will not be mentioned further in the following, more formal, description of the semantics of clauses.

The token |, when used outside a list, is an alias for ;. The aliasing is performed when terms are read in, so that

a :- b | c.

is read as if it were

a :- b ; c.

Note the double use of the . character. On the one hand it is used as a sentence terminator, while on the other it may be used in a string of symbols which make up an atom (e.g. the list functor ./2). The rule used to disambiguate terms is that a . followed by layout-text is regarded as a sentence terminator (see Token String).


Node:Declarative, Next:, Previous:Syntax, Up:Prolog Intro

Declarative Semantics

The semantics of definite clauses should be fairly clear from the informal interpretations already given. However it is useful to have a precise definition. The declarative semantics of definite clauses tells us which goals can be considered true according to a given program, and is defined recursively as follows.

A goal is true if it is the head of some clause instance and each of the goals (if any) in the body of that clause instance is true, where an instance of a clause (or term) is obtained by substituting, for each of zero or more of its variables, a new term for all occurrences of the variable.

For example, if a program contains the preceding procedure for concatenate/3, then the declarative semantics tells us that

?- concatenate([a], [b], [a,b]).

is true, because this goal is the head of a certain instance of the first clause for concatenate/3, namely,

concatenate([a], [b], [a,b]) :- concatenate([], [b], [b]).

and we know that the only goal in the body of this clause instance is true, since it is an instance of the unit clause which is the second clause for concatenate/3.


Node:Procedural, Next:, Previous:Declarative, Up:Prolog Intro

Procedural Semantics

Note that the declarative semantics makes no reference to the sequencing of goals within the body of a clause, nor to the sequencing of clauses within a program. This sequencing information is, however, very relevant for the procedural semantics which Prolog gives to definite clauses. The procedural semantics defines exactly how the Prolog system will execute a goal, and the sequencing information is the means by which the Prolog programmer directs the system to execute the program in a sensible way. The effect of executing a goal is to enumerate, one by one, its true instances. Here then is an informal definition of the procedural semantics. We first illustrate the semantics by the simple query

?- concatenate(X, Y, [a,b]).

We find that it matches the head of the first clause for concatenate/3, with X instantiated to [a|X1]. The new variable X1 is constrained by the new query produced, which contains a single recursive procedure call:

?- concatenate(X1, Y, [b]).

Again this goal matches the first clause, instantiating X1 to [b|X2], and yielding the new query:

?- concatenate(X2, Y, [])

Now the single goal will only match the second clause, instantiating both X2 and Y to []. Since there are no further goals to be executed, we have a solution

X = [a,b]
Y = []

i.e. a true instance of the original goal is

concatenate([a,b], [], [a,b])

If this solution is rejected, backtracking will generate the further solutions

X = [a]
Y = [b]

X = []
Y = [a,b]

in that order, by re-matching, against the second clause for concatenate, goals already solved once using the first clause.

Thus, in the procedural semantics, the set of clauses

H :- B1, ..., Bm.
H' :- B1', ..., Bm'.
...

are regarded as a procedure definition for some predicate H, and in a query

?- G1, ..., Gn.

each Gi is regarded as a procedure call. To execute a query, the system selects by its computation rule a goal, Gj say, and searches by its search rule a clause whose head matches Gj. Matching is done by the unification algorithm (see [Robinson 65] which computes the most general unifier, mgu, of Gj and H. The mgu is unique if it exists. If a match is found, the current query is reduced to a new query

?- (G1, ..., Gj-1, B1, ..., Bm, Gj+1, ..., Gn)mgu.

and a new cycle is started. The execution terminates when the empty query has been produced.

If there is no matching head for a goal, the execution backtracks to the most recent successful match in an attempt to find an alternative match. If such a match is found, an alternative new query is produced, and a new cycle is started.

In SICStus Prolog, as in other Prolog systems, the search rule is simple: "search forward from the beginning of the program".

The computation rule in traditional Prolog systems is also simple: "pick the leftmost goal of the current query". However, SICStus Prolog and other modern implementations have a somewhat more complex computation rule "pick the leftmost unblocked goal of the current query".

A goal can be blocked on one ore more uninstantiated variables, and a variable may block several goals. Thus binding a variable can cause blocked goals to become unblocked, and backtracking can cause currently unblocked goals to become blocked again. Moreover, if the current query is

?- G1, ..., Gj-1, Gj, Gj+1, ..., Gn.

where Gj is the first unblocked goal, and matching Gj against a clause head causes several blocked goals in G1, ..., Gj-1 to become unblocked, then these goals may become reordered. The internal order of any two goals that were blocked on the same variable is retained, however.

Another consequence is that a query may be derived consisting entirely of blocked goals. Such a query is said to have floundered. The top-level checks for this condition. If detected, the outstanding blocked subgoals are printed on the standard error stream along with the answer substitution, to notify the user that the answer (s)he has got is really a speculative one, since it is only valid if the blocked goals can be satisfied.

A goal is blocked if certain arguments are uninstantiated and its predicate definition is annotated with a matching block declaration (see Block Declarations). Goals of certain built-in may also be blocked if their arguments are not sufficiently instantiated.

When this mechanism is used, the control structure resembles that of coroutines, suspending and resuming different threads of control. When a computation has left blocked goals behind, the situation is analogous to spawning a new suspended thread. When a blocked goal becomes unblocked, the situation is analogous to temporarily suspending the current thread and resuming the thread to which the blocked goal belongs.


Node:Occur, Next:, Previous:Procedural, Up:Prolog Intro

Occurs-Check

It is possible, and sometimes useful, to write programs which unify a variable to a term in which that variable occurs, thus creating a cyclic term. The usual mathematical theory behind Logic Programming 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 (see Term Compare), assert, and copy cyclic terms without looping. The write_term/[2,3] built-in predicate can optionally handle cyclic terms; see Term I/O. Unification with occurs-check is available as a built-in predicate; see Misc Pred. Predicates testing (a)cyclicity are available in a library package; see Term Utilities. Other predicates usually do not handle cyclic terms well.


Node:Cut, Next:, Previous:Occur, Up:Prolog Intro

The Cut Symbol

Besides the sequencing of goals and clauses, Prolog provides one other very important facility for specifying control information. This is the cut symbol, written !. It is inserted in the program just like a goal, but is not to be regarded as part of the logic of the program and should be ignored as far as the declarative semantics is concerned.

The effect of the cut symbol is as follows. When first encountered as a goal, cut succeeds immediately. If backtracking should later return to the cut, the effect is to fail the parent goal, i.e. that goal which matched the head of the clause containing the cut, and caused the clause to be activated. In other words, the cut operation commits the system to all choices made since the parent goal was invoked, and causes other alternatives to be discarded. The goals thus rendered determinate are the parent goal itself, any goals occurring before the cut in the clause containing the cut, and any subgoals which were executed during the execution of those preceding goals.

For example:

member(X, [X|_]).
member(X, [_|L]) :- member(X, L).

This predicate can be used to test whether a given term is in a list. E.g.

| ?- member(b, [a,b,c]).

returns the answer yes. The predicate can also be used to extract elements from a list, as in

| ?- member(X, [d,e,f]).

With backtracking this will successively return each element of the list. Now suppose that the first clause had been written instead:

member(X, [X|_]) :- !.

In this case, the above call would extract only the first element of the list (d). On backtracking, the cut would immediately fail the whole predicate.

x :- p, !, q.
x :- r.

This is equivalent to

x := if p then q else r;

in an Algol-like language.

It should be noticed that a cut discards all the alternatives since the parent goal, even when the cut appears within a disjunction. This means that the normal method for eliminating a disjunction by defining an extra predicate cannot be applied to a disjunction containing a cut.

A proper use of the cut is usually a major difficulty for new Prolog programmers. The usual mistakes are to over-use cut, and to let cuts destroy the logic. A cut that doesn't destroy the logic is called a green cut; a cut that does is called a red cut. We would like to advise all users to follow these general rules. Also see Example Intro.


Node:Operators, Next:, Previous:Cut, Up:Prolog Intro

Operators

Operators in Prolog are simply a notational convenience. For example, the expression 2+1 could also be written +(2,1). This expression represents the compound term

   +
 /   \
2     1

and not the number 3. The addition would only be performed if the term were passed as an argument to an appropriate predicate such as is/2 (see Arithmetic).

The Prolog syntax caters for operators of three main kinds--infix, prefix and postfix. An infix operator appears between its two arguments, while a prefix operator precedes its single argument and a postfix operator is written after its single argument.

Each operator has a precedence, which is a number from 1 to 1200. The precedence is used to disambiguate expressions where the structure of the term denoted is not made explicit through the use of parentheses. The general rule is that it is the operator with the highest precedence that is the principal functor. Thus if + has a higher precedence than /, then

a+b/c     a+(b/c)

are equivalent and denote the term +(a,/(b,c)). Note that the infix form of the term /(+(a,b),c) must be written with explicit parentheses, i.e.

(a+b)/c

If there are two operators in the subexpression having the same highest precedence, the ambiguity must be resolved from the types of the operators. The possible types for an infix operator are

xfx     xfy     yfx

Operators of type xfx are not associative: it is a requirement that both of the two subexpressions which are the arguments of the operator must be of lower precedence than the operator itself, i.e. their principal functors must be of lower precedence, unless the subexpression is explicitly parenthesized (which gives it zero precedence).

Operators of type xfy are right-associative: only the first (left-hand) subexpression must be of lower precedence; the right-hand subexpression can be of the same precedence as the main operator. Left-associative operators (type yfx) are the other way around.

A functor named name is declared as an operator of type Type and precedence precedence by the directive:

:- op(precedence, type, name).

The argument name can also be a list of names of operators of the same type and precedence.

It is possible to have more than one operator of the same name, so long as they are of different kinds, i.e. infix, prefix or postfix. Note that the ISO Prolog standard contains a limitation that there should be no infix and postfix operators with the same name, however, SICStus Prolog lifts this restriction.

An operator of any kind may be redefined by a new declaration of the same kind. This applies equally to operators which are provided as standard, except for the ',' operator. Declarations of all the standard operators can be found elsewhere (see Standard Operators).

For example, the standard operators + and - are declared by

:- op(500, yfx, [ +, - ]).

so that

a-b+c

is valid syntax, and means

(a-b)+c

i.e.

     +
   /   \
  -     c
 / \
a   b

The list functor . is not a standard operator, but if we declare it thus:

:- op(900, xfy, .).

then a.b.c would represent the compound term

  .
 / \
a   .
   / \
  b   c

Contrasting this with the diagram above for a-b+c shows the difference between yfx operators where the tree grows to the left, and xfy operators where it grows to the right. The tree cannot grow at all for xfx operators; it is simply illegal to combine xfx operators having equal precedences in this way.

The possible types for a prefix operator are

fx      fy

and for a postfix operator they are

xf      yf

The meaning of the types should be clear by analogy with those for infix operators. As an example, if not were declared as a prefix operator of type fy, then

not not P

would be a permissible way to write not(not(P)). If the type were fx, the preceding expression would not be legal, although

not P

would still be a permissible form for not(P).

If these precedence and associativity rules seem rather complex, remember that you can always use parentheses when in any doubt.

Note that the arguments of a compound term written in standard syntax must be expressions of precedence below 1000. Thus it is necessary to parenthesize the expression P :- Q in

| ?- assert((P :- Q)).


Node:Restrictions, Next:, Previous:Operators, Up:Prolog Intro

Syntax Restrictions

Note carefully the following syntax restrictions, which serve to remove potential ambiguity associated with prefix operators.

  1. In a term written in standard syntax, the principal functor and its following ( must not be separated by any intervening layout-text. Thus
    point (X,Y,Z)
    

    is invalid syntax.

  2. If the argument of a prefix operator starts with a (, this ( must be separated from the operator by at least one layout-char. Thus
    :-(p;q),r.
    

    (where :- is the prefix operator) is invalid syntax. The system would try to interpret it as the compound term:

        ,
       / \
     :-    r
      |
      ;
     / \
    p   q
    

    That is, it would take :- to be a functor of arity 1. However, since the arguments of a functor are required to be expressions of precedence below 1000, this interpretation would fail as soon as the ; (precedence 1100) was encountered.

    In contrast, the term:

    :- (p;q),r.
    

    is valid syntax and represents the following compound term:

       :-
        |
        ,
       / \
      ;   r
     / \
    p   q
    


Node:Comments, Previous:Restrictions, Up:Prolog Intro

Comments

Comments have no effect on the execution of a program, but they are very useful for making programs more readily comprehensible. Two forms of comment are allowed in Prolog:

  1. The character % followed by any sequence of characters up to end of line.
  2. The symbol /* followed by any sequence of characters (including new lines) up to */.


Node:Module Intro, Next:, Previous:Prolog Intro, Up:Top

The Module System

By making use of the module systems facilities, programs can be divided into different modules. Each module has its own independent predicate name space. This is an important feature for the development of larger programs. The module system of SICStus Prolog is procedure based. This means that only the predicates are local to a module, whereas terms are global. The module system is flat, not hierarchical, so all modules are visible to one another. It is non-strict, i.e. the normal visibility rules can be overridden by special syntax. No overhead is incurred on compiled calls to predicates in other modules. It is modeled after and compatible with the Quintus Prolog module system. Finally, using the module system is optional, and SICStus Prolog may be used without the user being aware of the module system at all.

Modules in SICStus Prolog can also be used for object-oriented programming. See Obj Intro, for details.


Node:Basic Concepts, Next:, Previous:Module Intro, Up:Module Intro

Basic Concepts

Each predicate in the Prolog system, whether built-in or user defined, belongs to a module. A predicate is generally only visible in the module where it is defined. However a predicate may be imported by another module. It is thereby made visible in that module too. Built-in predicates are visible in every module. Predicates declared as public in a module declaration (see below) are exported. Normally only public predicates may be imported by another module.

For any given goal, the source module is the module in which the corresponding predicate must be visible. Similarly, for any given clause, the source module of its head is the module into which the clause is loaded.

For goals occurring in a source file with a module declaration, the source module is the declared module. For goals occurring in a source file without a module declaration, the source module is the module that the file is being loaded into. For goals typed at the top level, the source module is the type-in module. The type-in module is by default the user module but may be changed by the built-in predicate module/1.

The other predefined module is the prolog module where all the built-in predicates reside. The exported built-in predicates are automatically imported into each new module as it is created.


Node:Module Spec, Next:, Previous:Basic Concepts, Up:Module Intro

Module Prefixing

Notwithstanding the visibility rules, any predicate can be called from any other module by prefixing the goal with the module name and the colon operator, thus overriding the source module of the goal:

| ?- foo:bar(X).

This feature is intended mainly for debugging purposes, since it defies the purposes of the module system. If the prefixed goal is a meta-predicate, however, the prefixed module name may affect the module name expansion of the goal (see Meta Exp). If multiple module prefixes are used, the innermost one has priority.

It is also possible to override the source module of clauses and directives by module prefixing. For example,

:- dynamic mod:p/1.
p(X) :- mod:(q(X), r(X)).
mod:(q(X) :- r(X)).
mod:s(X) :- t(X).

declares mod:p/1 as dynamic, whatever the source module is; defines p/1 in the source module as calling mod:q/1 and mod:r/1; defines mod:q/1 as calling mod:r/1; and defines mod:s/1 as calling t/1 in the source module. The latter technique is particularly useful when the prefix is user and the predicate is a hook predicate such as user:portray/1 which must be defined in the user module, but the rest of the file consists of predicates belonging to some other module.


Node:Def Modules, Next:, Previous:Module Spec, Up:Module Intro

Defining Modules

A module is normally defined by putting a module declaration in a source file. A module declaration has the form:

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

and should precede all other clauses and directives of that file.

When the file is loaded, all predicates in the file go into ModuleName and the predicates of the ExportList are exported. When a module declaration is processed, all existing predicates in the module are erased before the new ones are loaded. A file which contains a module declaration is henceforth called a module-file.

Options is an optional argument, and should be a list. The only available option is hidden(Boolean), where Boolean is false (the default) or true. In the latter case, tracing of the predicates of the module is disabled (although spypoints can be set), and no source information is generated at compile time.

A module can also be defined dynamically by asserting or loading predicates to it:

| ?- assert(m:p(x)).

creates the module m, if it does not already exists, and asserts p(x) to it.

| ?- compile(m:f).

creates the module m and loads f into m.

Dynamically created modules have no public predicates.


Node:Importation, Next:, Previous:Def Modules, Up:Module Intro

Importation

When a module-file is loaded by load_files/[1,2] or one of its shorthands (see Read In), by default all the public predicates of the module-file are imported by the receiving module. An explicit list of predicates to import may also be specified.

Clashes with already existing predicates, local or imported from other modules, are handled in two different ways: If the receiving module is the user module, the user is asked for redefinition of the predicate. For other receiving modules, a warning is issued and the importation is canceled. In the first case redefinition silently takes place if the flag redefine_warnings has the value off (see prolog_flag/3). The binding of an imported predicate remains, even if the origin is reloaded or deleted. However, abolish/[1,2] break up the importation binding. When a module-file is reloaded, a check is made that the predicates imported by other modules are still in the public list. If that is not the case, a warning is issued. Note that an imported predicate may be re-exported.


Node:Meta Exp, Next:, Previous:Importation, Up:Module Intro

Module Name Expansion

Some predicates take goals as arguments (i.e. meta-predicates). These arguments must include a module specification stating which module the goal refers. Some other predicates also need module information i.e. compile/1. The property of needing module information is declared with a meta-predicate declaration (see Meta Decl). Goals for these predicates are module name expanded to ensure the module information. Goals appearing in queries and meta-calls are expanded prior to execution while goals in the bodies of clauses and directives are expanded at compile time. The expansion is made by preceding the relevant argument with Module:. If the goal is prefixed by Module:, Module is used for the expansion, otherwise the source/type-in module is used. An argument is not expanded if:

Some examples:

| ?- [user].
| :- meta_predicate p(:), q(:).
| r(X) :- p(X).
| q(X) :- p(X).
| ^D
{user consulted, 40 msec 1088 bytes}

yes
| ?- listing.

r(A) :-
        p(user:A).

q(A) :-
        p(A).

yes

Here, p/1 and q/1 are declared as meta-predicates while r/1 is not. Thus the clause r(X) :- p(X) will be transformed to r(X) :- p(M:X), by item 2 above, where M is the type-in module, whereas q(X) :- p(X) will not.

| ?- m:assert(f(1)).

Here, assert/1 is called in the module m. However, this does not ensure that f(1) is asserted into m. The fact that assert/1 is a meta-predicate makes the system module name expand the goal, transforming it to m:assert(m:f(1)) before execution. This way, assert/1 is supplied the correct module information.


Node:Meta Decl, Previous:Meta Exp, Up:Module Intro

Meta-Predicate Declarations

The fact that a predicate needs module name expansion is declared in a meta-predicate declaration:

:- meta_predicate MetaPredSpec, ..., MetaPredSpec.

where each MetaPredSpec is a mode spec. E.g.

:- meta_predicate p(:, +).

which means that the first argument of p/2 shall be module name expanded. The arguments in the mode spec are interpreted as:

:
An integer
This argument, in any call to the declared predicate, shall be expanded. (Integers are allowed for compatibility reasons).
Anything else e.g. +, - or ?
This argument shall not be expanded

A number of built-in predicates have predefined meta-predicate declarations, as indicated by the mode specs in this manual, e.g. call(:Term).


Node:Load Intro, Next:, Previous:Module Intro, Up:Top

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 Misc Pred).

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 four 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 Sparc platforms. 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 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 query:

| ?- prolog_flag(compiling, OldValue, NewValue).

A Prolog program consists of a sequence of sentences (see Sentence). Directives encountered among the sentences are executed immediately as they are encountered, unless they can be interpreted as declarations (see Declarations), which affect the treatment of forthcoming clauses, or as initializations, which build up a set of goals to be executed after the program has been loaded. 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 Definite) "return" a list of sentences, instead of a single sentence.


Node:Load Predicates, Next:, Previous:Load Intro, Up:Load Intro

Predicates which Load Code

This section contains a summary of the relevant predicates. For a more precise description, see Read In.

To consult a program, issue the query:

| ?- consult(Files).

where Files is either a filename 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 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 Module Intro).

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 Reading In).

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.

Programs can be compiled into an intermediate representation known as .ql (for Quick Load file). As of SICStus Prolog 3.8, this feature is obsolescent with the introduction of partial saved states (.po files, see Saving), which can be handled much more efficiently.

To compile a program into a .ql 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 a .ql file. The filename is 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 Considerations.

To load a program from a set of source or object files, use the built-in predicates load_files/[1,2] (the latter is controlled by an options list):

| ?- load_files(Files).

where Files is either a single filename or a list of filenames, optionally with .pl or .po or .ql extensions. This predicate takes the following action for each File in the list of filenames:

  1. If the File is user, compile(user) or [user] is performed;
  2. If File cannot be found, not even with an extension, an existence error is signaled;
  3. If an .po file is found, the file is loaded;
  4. If an .ql file is found, the file is loaded;
  5. If a source file is found, the file is compiled or consulted.
  6. If more than one file is found for File, item 3 or 4 or 5 applies depending on which file was modified most recently.
  7. If File cannot be found, not even with an extension, an existence error is signaled.
  8. Source files are compiled, unless load_files/1 was called from a directive of a file being consulted.

Finally, to ensure that some files have been loaded, use the built-in predicate:

| ?- ensure_loaded(Files).

Same as load_files(Files), except if the file to be loaded has already been loaded and has not been modified since that time, in which case the file is not loaded again. If a source file has been modified, ensure_loaded/1 does not cause any object file to become recompiled.


Node:Declarations, Next:, Previous:Load Predicates, Up:Load Intro

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 directive, 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 directives 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.


Node:Multifile Declarations, Next:, Previous:Declarations, Up:Declarations

Multifile Declarations

A declaration

:- multifile PredSpec, ..., PredSpec.  [ISO]

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. By default, hook predicates must be defined in the user module, and only their first solution is relevant.

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)!


Node:Dynamic Declarations, Next:, Previous:Multifile Declarations, Up:Declarations

Dynamic Declarations

A declaration

:- dynamic PredSpec, ..., PredSpec.  [ISO]

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.


Node:Volatile Declarations, Next:, Previous:Dynamic Declarations, Up:Declarations

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.


Node:Discontiguous Declarations, Next:, Previous:Volatile Declarations, Up:Declarations

Discontiguous Declarations

A declaration

:- discontiguous PredSpec, ..., PredSpec.  [ISO]

where each PredSpec is a predicate spec, disables warnings about clauses not being together for the specified predicates. By default, such warnings are issued in development systems unless disabled selectively for specific predicates, or globally by setting the discontiguous_warnings flag to off.


Node:Block Declarations, Next:, Previous:Discontiguous Declarations, Up:Declarations

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 Use Of Term Exp, for a simple way to extend the system to accept the old syntax.


Node:Meta-Predicate Declarations, Next:, Previous:Block Declarations, Up:Declarations

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 Meta Exp, for details.


Node:Module Declarations, Next:, Previous:Meta-Predicate Declarations, Up:Declarations

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 Def Modules, for details.


Node:Public Declarations, Next:, Previous:Module Declarations, Up:Declarations

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. This declaration is obsolescent. See Module Intro.


Node:Mode Declarations, Next:, Previous:Public Declarations, Up:Declarations

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.


Node:Include Declarations, Previous:Mode Declarations, Up:Declarations

Include Declarations

A declaration

:- include(Files).  [ISO]

where Files is a file name or a list of file names, instructs the processor to literally embed the Prolog clauses and directives in Files into the file being loaded. This means that the effect of the include directive is such as if the include directive itself was replaced by the text in the Files. Including some files is thus different from loading them in several respects:

SICStus Prolog uses the included file name (as opposed to the embedding file name) only in source level debugging and error reporting. Note that source level debugging information is not kept for included files which are compiled to .ql format; in such cases the debugger will show the include directive itself as the source information.


Node:Initializations, Next:, Previous:Declarations, Up:Load Intro

Initializations

A directive

:- initialization :Goal.  [ISO]

in a file includes Goal to the set of goals which shall be executed after that file has been loaded.

initialization/1 is actually callable at any point during loading of a file. Initializations are saved by save_modules/2 and save_program/[1,2], and so are executed after loading or restoring such files too.

Goal is associated with the file loaded, and with a module, if applicable. When a file, or module, is going to be reloaded, all goals earlier installed by that file, or in that module, are removed first.


Node:Considerations, Previous:Initializations, Up:Load Intro

Considerations for File-To-File Compilation

When compiling a source file to a .ql 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 .ql 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 .ql 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 .ql file is loaded into a different module from which it was compiled for, a warning is issued.


Node:Debug Intro, Next:, Previous:Load Intro, Up:Top

Debugging

This chapter describes the debugging facilities that are available in development systems. The purpose of these facilities is to provide information concerning the control flow of your program.

The main features of the debugging package are as follows:

The Procedure Box model of execution is also called the Byrd Box model after its inventor, Lawrence Byrd.

Much of the information in this chapter is also in Chapter eight of [Clocksin & Mellish 81] which is recommended as an introduction.

Unless otherwise stated, the debugger prints goals using write_term/3 with the value of the Prolog flag debugger_print_options (see State Info).

The debugger is not available in runtime systems and the predicates defined in this chapter are undefined; see Runtime Systems.


Node:Procedure Box, Next:, Previous:Debug Intro, Up:Debug Intro

The Procedure Box Control Flow Model

During debugging, the debugger prints out a sequence of goals in various states of instantiation in order to show the state the program has reached in its execution. However, in order to understand what is occurring it is necessary to understand when and why the debugger prints out goals. As in other programming languages, key points of interest are predicate entry and return, but in Prolog there is the additional complexity of backtracking. One of the major confusions that novice Prolog programmers have to face is the question of what actually happens when a goal fails and the system suddenly starts backtracking. The Procedure Box model of Prolog execution views program control flow in terms of movement about the program text. This model provides a basis for the debugging mechanism in development systems, and enables the user to view the behavior of the program in a consistent way.

Let us look at an example Prolog predicate :

           *--------------------------------------*
   Call    |                                      |    Exit
---------> +  descendant(X,Y) :- offspring(X,Y).  + --------->
           |                                      |
           |  descendant(X,Z) :-                  |
<--------- +     offspring(X,Y), descendant(Y,Z). + <---------
   Fail    |                                      |    Redo
           *-------------------+------------------*
                               |
<------------------------------+
   Exception

The first clause states that Y is a descendant of X if Y is an offspring of X, and the second clause states that Z is a descendant of X if Y is an offspring of X and if Z is a descendant of Y. In the diagram a box has been drawn around the whole predicate and labeled arrows indicate the control flow in and out of this box. There are five such arrows which we shall look at in turn.

Call
This arrow represents initial invocation of the predicate. When a goal of the form descendant(X,Y) is required to be satisfied, control passes through the Call port of the descendant box with the intention of matching a component clause and then satisfying the subgoals in the body of that clause. Note that this is independent of whether such a match is possible; i.e. first the box is called, and then the attempt to match takes place. Textually we can imagine moving to the code for descendant when meeting a call to descendant in some other part of the code.
Exit
This arrow represents a successful return from the predicate. This occurs when the initial goal has been unified with one of the component clauses and the subgoals have been satisfied. Control now passes out of the Exit port of the descendant box. Textually we stop following the code for descendant and go back to the place we came from.
Redo
This arrow indicates that a subsequent goal has failed and that the system is backtracking in an attempt to find alternatives to previous solutions. Control passes through the Redo port of the descendant box. An attempt will now be made to resatisfy one of the component subgoals in the body of the clause that last succeeded; or, if that fails, to completely rematch the original goal with an alternative clause and then try to satisfy any subgoals in the body of this new clause. Textually we follow the code backwards up the way we came looking for new ways of succeeding, possibly dropping down on to another clause and following that if necessary.
Fail
This arrow represents a failure of the initial goal, which might occur if no clause is matched, or if subgoals are never satisfied, or if any solution produced is always rejected by later processing. Control now passes out of the Fail port of the descendant box and the system continues to backtrack. Textually we move back to the code which called this predicate and keep moving backwards up the code looking for choice points.
Exception
This arrow represents an exception which was raised in the initial goal, either by a call to raise_exception/1 or by an error in a built-in predicate. See Exception. Control now passes out of the Exception port of the descendant box and the system continues to pass the exception to outer levels. Textually we move back to the code which called this predicate and keep moving backwards up the code looking for a call to on_exception/3.

In terms of this model, the information we get about the procedure box is only the control flow through these five ports. This means that at this level we are not concerned with which clause matches, and how any subgoals are satisfied, but rather we only wish to know the initial goal and the final outcome. However, it can be seen that whenever we are trying to satisfy subgoals, what we are actually doing is passing through the ports of their respective boxes. If we were to follow this, then we would have complete information about the control flow inside the procedure box.

Note that the box we have drawn round the predicate should really be seen as an invocation box. That is, there will be a different box for each different invocation of the predicate. Obviously, with something like a recursive predicate, there will be many different Calls and Exits in the control flow, but these will be for different invocations. Since this might get confusing each invocation box is given a unique integer identifier.

In addition to the five basic ports discussed above, there are two more ports for invocations involving a blocked goal:

Block
This port is passed through when a goal is blocked.
Unblock
This port is passed through when a previously blocked goal is unblocked.


Node:Basic Debug, Next:, Previous:Procedure Box, Up:Debug Intro

Basic Debugging Predicates

Development systems provide a range of built-in predicates for control of the debugging facilities. The most basic predicates are as follows:

debug

Switches the debugger on, and ensures that the next time control reaches a spypoint, it will be activated. In basic usage this means that a message will be produced and you will be prompted for a command. In order for the full range of control flow information to be available it is necessary to have the debugger on from the start. When it is off the system does not remember invocations that are being executed. (This is because it is expensive and not required for normal running of programs.) You can switch Debug Mode on in the middle of execution, either from within your program or after a ^C (see trace/0 below), but information prior to this will just be unavailable.

zip

Same as debug/0, except no debugging information is being collected, and so is almost as fast as running with the debugger switched off.

trace

Switches the debugger on, and ensures that the next time control enters an invocation box, a message will be produced and you will be prompted for a command. The effect of trace can also be achieved by typing t after a ^C interruption of a program.

At this point you have a number of options. See Debug Commands. In particular, you can just type <RET> to creep (or single-step) into your program. If you continue to creep through your program you will see every entry and exit to/from every invocation box, including compiled code, except for code belonging to hidden modules (see Def Modules). You will notice that the debugger stops at all ports. However, if this is not what you want, the following built-in predicate gives full control over the ports at which you are prompted:

leash(+Mode)

Leashing Mode is set to Mode. Leashing Mode determines the ports of invocation boxes at which you are to be prompted when you Creep through your program. At unleashed ports a tracing message is still output, but program execution does not stop to allow user interaction. Note that leash/1 does not apply to spypoints, the leashing mode of these can be set using the advanced debugger features; see Breakpoints. Mode can be a subset of the following, specified as a list:

call
Prompt on Call.
exit
Prompt on Exit.
redo
Prompt on Redo.
fail
Prompt on Fail.
exception
Prompt on Exception.

The initial value of Leashing Mode is [call,exit,redo,fail,exception] (full leashing).

nodebug
notrace
nozip

Switches the debugger off. If there are any spypoints set then they will be kept but will never be activated.

debugging

Prints information about the current debugging state. This will show:

  1. Whether undefined predicates are being trapped.
  2. What breakpoints have been set (see below).
  3. What mode of leashing is in force (see above).


Node:Plain Spypoint, Next:, Previous:Basic Debug, Up:Debug Intro

Plain Spypoints

For programs of any size, it is clearly impractical to creep through the entire program. Spypoints make it possible to stop the program whenever it gets to a particular predicate which is of interest. Once there, one can set further spypoints in order to catch the control flow a bit further on, or one can start creeping.

In this section we discuss the simplest form of spypoints, the plain spypoints. The more advanced forms, the conditional and generic spypoints will be discussed later; see Breakpoints.

Setting a plain spypoint on a predicate indicates that you wish to see all control flow through the various ports of its invocation boxes, except during skips. When control passes through any port of an invocation box with a spypoint set on it, a message is output and the user is asked to interact. Note that the current mode of leashing does not affect plain spypoints: user interaction is requested on every port.

Spypoints are set and removed by the following built-in predicates. The first two are also standard operators:

spy :Spec

Sets plain spypoints on all the predicates given by the generalized predicate spec Spec.

Examples:

| ?- spy [user:p, m:q/[2,3]].
| ?- spy m:[p/1, q/1].

If you set some spypoints when the debugger is switched off then it will be automatically switched on, entering zip mode.

nospy :Spec

Similar to spy Spec except that all the predicates given by Spec will have all previously set spypoints removed from them (including conditional spypoints; see Breakpoints).

nospyall

Removes all the spypoints, including the conditional ones, that have been set.

The commands available when you arrive at a spypoint are described later. See Debug Commands.


Node:Debug Format, Next:, Previous:Plain Spypoint, Up:Debug Intro

Format of Debugging Messages

We shall now look at the exact format of the message output by the system at a port. All trace messages are output to the standard error stream, using the print_message/2 predicate; see Exception. This allows you to trace programs while they are performing file I/O. The basic format is as follows:

N S    23     6 Call: T foo(hello,there,_123) ?

N is only used at Exit ports and indicates whether the invocation could backtrack and find alternative solutions. Unintended non-determinism is a source of inefficiency, and this annotation can help spot such efficiency bugs. It is printed as ?, indicating that foo/3 could backtrack and find alternative solutions, or otherwise.

S is a spypoint indicator. If there is a plain spypoint on foo/3, it is printed as +. In case of conditional and generic spypoints it takes the form * and #, respectively. Finally, it is printed as , if there is no spypoint on the predicate being traced.

The first number is the unique invocation identifier. It is nondecreasing regardless of whether or not you are actually seeing the invocations (provided that the debugger is switched on). This number can be used to cross correlate the trace messages for the various ports, since it is unique for every invocation. It will also give an indication of the number of procedure calls made since the start of the execution. The invocation counter starts again for every fresh execution of a command, and it is also reset when retries (see later) are performed.

The number following this is the current depth; i.e. the number of direct ancestors this goal has.

The next word specifies the particular port (Call, Exit, Redo, Fail, or Exception).

T is a subterm trace. This is used in conjunction with the ^ command (set subterm), described below. If a subterm has been selected, T is printed as the sequence of commands used to select the subterm. Normally, however, T is printed as , indicating that no subterm has been selected.

The goal is then printed so that you can inspect its current instantiation state.

The final ? is the prompt indicating that you should type in one of the commands allowed (see Debug Commands). If this particular port is unleashed then you will obviously not get this prompt since you have specified that you do not wish to interact at this point.

At Exception ports, the trace message is preceded by a message about the pending exception, formatted as if it would arrive uncaught at the top level.

Note that calls that are compiled in-line and built-in predicates that are called directly from the top level are not traced.

Block and unblock ports are exceptions to the above debugger message format. A message

       S -  -  Block: p(_133)

indicates that the debugger has encountered a blocked goal, i.e. one which is temporarily suspended due to insufficiently instantiated arguments (see Procedural). By default, no interaction takes place at this point, and the debugger simply proceeds to the next goal in the execution stream. The suspended goal will be eligible for execution once the blocking condition ceases to exist, at which time a message

       S -  -  Unblock: p(_133)

is printed. Although Block and Unblock ports are unleashed by default in trace mode, you can make the debugger interact at these ports by using conditional spypoints.


Node:Breakpoints, Next:, Previous:Debug Format, Up:Debug Intro

Breakpoints

This section gives an overview of the advanced debugger features. These center around the notion of breakpoint, a generalization of the plain spypoint introduced earlier. The details of built-in predicates dealing with breakpoints are given in Breakpoint Predicates and in Breakpoint Conditions.

A breakpoint is specified by providing the conditions under which the breakpoint applies and its effect on the execution. Syntactically, the breakpoint is given as a pair of two lists of conditions. The first list, the tests, contains the tests for the applicability of the breakpoint, the second, the actions describes the effects of the breakpoint on the execution. Example:

| ?- add_breakpoint([goal(foo(1,_)),port(call)]-
                      [show(display),command(proceed)],
                    BID).

This invocation of the add_breakpoint/2 built-in predicate creates a breakpoint which will apply to goals which unify with foo(1,_) and only to their call ports -- this is the test part. The second list, the action part specifies that the debugger should show the debugged goal using display/1 and should proceed without stopping, whenever the breakpoint is applicable. The add_breakpoint/2 built-in returns a BID, a numeric breakpoint identifier.

There are two types of breakpoints, advice and debugger. These are distinguished by the presence of conditions advice and debugger, the latter being the default. Debugger breakpoints are also called spypoints. Spypoints apply only when the debugger is switched on. Advice breakpoints, or advice-points, apply irrespectively of the debugger state. Advice is checked even inside hook predicates.

The most important test condition is goal(M:Goal). This makes the breakpoint applicable only to invocations whose goal and module matches Goal and M. A breakpoint with a goal condition where both the module and the goal are non-variable is called a specific breakpoint. If any of these is a variable (or there is no goal condition), the breakpoint is generic. The presence of a generic breakpoint slows down the execution, as its conditions have to be examined at every predicate invocation. Specific breakpoints, on the other hand, are handled efficiently, as only the execution of the specified predicate is affected.

The following example shows the creation of a generic breakpoint.

| ?- add_breakpoint([advice,port(call)]-
                      [line(L),true(assert(line_reached(L)))],
                    BID).

This advice-point will apply to all predicates (or more precisely to all predicates in the module in question -- as the conditions argument is subject to module name expansion; see Goal Tests). Whenever a call port is reached, the action part of the breakpoint gets hold of the source line number (if available) and asserts a fact with this number. Here the condition true(PrologCondition) executes PrologCondition as a Prolog goal and succeeds accordingly. An advice breakpoint of this kind can be used for profiling or branch-coverage analysis.

The pred condition is a variant of the goal condition: pred(F/N) is equivalent to goal(Goal), where Goal is the most general term with the functor F/N. A specific spypoint whose conditions consist of a single pred condition (or an equivalent goal condition) is the same as the plain spypoint introduced earlier; see Plain Spypoint. Specific spypoints which are not plain, are called conditional spypoints. For example, the following three goals have the same effect, creating a plain spypoint for predicate foo/2:

| ?- add_breakpoint(pred(foo/2), _).
| ?- add_breakpoint(goal(foo(_,_)), _).
| ?- spy foo/2.

The effect of the breakpoint on the execution is specified by the actions list. In the case of spypoints, the action part may specify values for the following three debugger action variables:

If no actions are specified at a spypoint, the default [command(ask),show(print)] is assumed.

In the case of advice-points only the command action can be specified, its meaning will be explained later. Here the default is not to apply any actions.

The action part can contain the other conditions allowed in the test part, too. The advice-point example above uses the line(L) condition in the action part, as the applicability of the breakpoint does not depend on the line number. This can be contrasted with the the following example, where the success of the conditions does depend on the line number, and so the line condition appears in the test part:

add_breakpoint([line(Line),true((Line>=20,Line=<40))], _).

This example introduces a generic spypoint which applies to invocations appearing between lines 20-40.

We have seen the true condition being used in both the test and the action part. If it is used for testing (i.e. it can fail), it should be placed in the test part. On the other hand, it should appear in the action part if it has a side effect, e.g. asserts some clauses or writes out a message. This is because the test part of spypoint conditions may be evaluated multiple times for a single port.

Note that this distinction between the test part and the action part is not strictly enforced. If a condition in the action part fails, the breakpoint will not be applied, but, of course, the side effects preceding the failed condition will have already taken place.

Having created some breakpoints, you can use the built-in predicate current_breakpoint/4 to enumerate all breakpoints together with their properties. By reference to their identifiers breakpoints can be removed, temporarily disabled, or enabled.

Naturally, there can be multiple breakpoints at any given time of execution. They are handled in a stack-like discipline, i.e. the most recent breakpoints (the ones with higher breakpoint identifiers) are tried first. At each port the debugger first looks for enabled advice-points, the first (most recent) one found applicable is then activated, i.e. its action part is executed. Subsequently the debugger scans the breakpoint stack again, looking for an enabled spypoint applicable for the current invocation, and again the first such spypoint is activated. For the details of how the breakpoints are processed, see Breakpoint Processing.

As explained earlier, when the system is in Debug Mode, the debugger collects control flow information about the goals being executed. This collection of information, the backtrace, includes the invocations that were called but not exited yet, as well as those that exited non-deterministically. For each invocation, the main data items present in the backtrace are the following: the goal, the module, the invocation number, the depth and the source information, if any. There is also a field in the backtrace reserved for the user, initially an empty variable. The goal_private(_) condition unifies its argument with this field. We will show an example on how to use the goal_private field to transfer instantiation information from the call port to the exit port; see Breakpoint Example.

When an invocation is at the call port, the user can decide not to build a procedure box for the invocation and not to put it on the backtrace. This can be done by supplying the action command(flit). In this case the execution continues without building the procedure box, and with much smaller space overhead then otherwise.1 This also means, of course, that the execution will not stop at the remaining ports of this invocation. The command(flit) is the only meaningful execution control action that can be used for advice-points.

The backtrace can be accessed outside the debugger, too, via the built-in predicates execution_state/[1,2]. The predicate execution_state(Tests) accesses the current execution state. Arbitrary tests can be used in this predicate, if it is called from within a true condition in an add_breakpoint/2. For example the advice breakpoint shown earlier can be simplified to:

[advice,call]-true(assert_line)

The current line number then can be accessed from within assert_line:

assert_line :-
       execution_state(line(L)), assert(line_reached(L)).

Note that we applied some syntactic simplifications in the above texts. First, we simplified port(call) to call: for certain tests, which have a pre-defined range of possible arguments, the name of the test is automatically inserted if a concrete argument is given. Second, we omitted the square brackets around the action part: this is applicable to both tests and actions, if they contain a single condition only.

Invoking execution_state/1 can also be useful inside the user:debugger_command_hook/2 predicate, which serves for defining new interactive debugger commands.

If execution_state/1 is called outside the debugger, only some tests are available, e.g. those querying to data stored in the backtrace.

The execution_state/2 predicate lets us examine past elements of the backtrace. For example:

execution_state(inv(N), goal(Goal))

retrieves the Goal stored in the backtrace under invocation number N.

The debugger is also able to keep track of multiple backtraces associated with different break levels. We can access data stored in previous break levels, using execution_state/2, as e.g. in:

execution_state([break_level(0),inv(N)], goal(Goal))

This example accesses the Nth invocation of the outermost break level. Such use can be helpful if one enters a break during tracing, and wants to access the outer backtrace from within the break.


Node:Debug Commands, Next:, Previous:Breakpoints, Up:Debug Intro

Commands Available during Debugging

This section describes the particular commands that are available when the system prompts you after printing out a debugging message. All the commands are one or two letter mnemonics, some of which can be optionally followed by a decimal integer. They are read from the standard input stream with any blanks being completely ignored up to the end of the line (<RET>). Some commands only actually require the terminator; e.g. the creep command, as we have already seen, only requires <RET>.

The only command which you really have to remember is h (followed by <RET>). This provides help in the form of the following list of available commands.

   <cr>   creep            c      creep
    l     leap             z      zip
    s     skip             s <i>  skip i
    o     out              o <n>  out n
    q     q-skip           q <i>  q-skip i
    r     retry            r <i>  retry i
    f     fail             f <i>  fail i
    j<p>  jump to port     j<p><i>jump to port i
    d     display          w      write
    p     print            p <i>  print partial
    g     ancestors        g <n>  ancestors n
    t     backtrace        t <n>  backtrace n
    &     blocked goals    & <n>  nth blocked goal
    n     nodebug          =      debugging
    +     spy this         *      spy conditionally
    -     nospy this       \ <i>  remove brkpoint
    D <i> disable brkpoint E <i>  enable brkpoint
    a     abort            b      break
    @     command          u      unify
    e     raise exception  .      find this
    <     reset printdepth < <n>  set printdepth
    ^     reset subterm    ^ <n>  set subterm
    ?     help             h      help
c
<RET>
creep causes the debugger to single-step to the very next port and print a message. Then if the port is leashed (see Basic Debug), the user is prompted for further interaction. Otherwise, it continues creeping. If leashing is off, creep is the same as leap (see below) except that a complete trace is printed on the standard error stream.
l
leap causes the debugger to resume running your program, only stopping when a spypoint is reached (or when the program terminates). Leaping can thus be used to follow the execution at a higher level than exhaustive tracing. All you need to do is to set spypoints on an evenly spread set of pertinent predicates, and then follow the control flow through these by leaping from one to the other. Debugging information is collected while leaping, so when a spypoint is reached, it is possible to inspect the ancestor goals, or creep into them upon entry to Redo ports.
z
zip is like leap, except no debugging information is being collected while zipping, resulting in significant savings in memory and execution time.
s
skip is only valid for Call and Redo ports. It skips over the entire execution of the predicate. That is, you will not see anything until control comes back to this predicate (at either the Exit port or the Fail port). Skip is particularly useful while creeping since it guarantees that control will be returned after the (possibly complex) execution within the box. If you skip then no message at all will appear until control returns. This includes calls to predicates with spypoints set; they will be masked out during the skip. No debugging information is being collected while skipping.

If you supply an integer argument, then this should denote an invocation number of an ancestral goal. The system tries to get you to the Exit or Fail port of the invocation box you have specified.

o
out is a shorthand for skipping to the Exit or Fail port of the immediate ancestor goal. If you supply an integer argument n, it denotes skipping to the Exit or Fail port of the nth ancestor goal.
q
quasi-skip is like a combination of zip and skip: execution stops when either control comes back to this predicate, or a spypoint is reached. No debugging information is being collected while quasi-skipping.

An integer argument can be supplied as for skip.

r
retry can be used at any of the four ports (although at the Call port it has no effect). It transfers control back to the Call port of the box. This allows you to restart an invocation when, for example, you find yourself leaving with some weird result. The state of execution is exactly the same as when you originally called, (unless you use side effects in your program; i.e. asserts etc. will not be undone). When a retry is performed the invocation counter is reset so that counting will continue from the current invocation number regardless of what happened before the retry. This is in accord with the fact that you have, in executional terms, returned to the state before anything else was called.

If you supply an integer argument, then this should denote an invocation number of an ancestral goal. The system tries to get you to the Call port of the box you have specified. It does this by continuously failing until it reaches the right place. Unfortunately this process cannot be guaranteed: it may be the case that the invocation you are looking for has been cut out of the search space by cuts (!) in your program. In this case the system fails to the latest surviving Call port before the correct one.

f
fail can be used at any of the four ports (although at the Fail port it has no effect). It transfers control to the Fail port of the box, forcing the invocation to fail prematurely.

If you supply an integer after the command, then this is taken as specifying an invocation number and the system tries to get you to the Fail port of the invocation box you have specified. It does this by continuously failing until it reaches the right place. Unfortunately this process cannot be guaranteed: it may be the case that the invocation you are looking for has been cut out of the search space by cuts (!) in your program. In this case the system fails to the latest surviving Fail port before the correct one.

j<p>
jump to port transfers control back to the prescribed port <p>. Here <p> is one of: c, e, r, f, standing for Call, Exit, Redo and Fail ports. Takes an optional integer argument, an invocation number.

Jumping to a call port is the same as retrying it, i.e. jc is the same as the r debugger command; and similarly jf is the same as f.

The je jump to Exit port command transfers control back to the Exit port of the box. It can be used at a Redo or an Exit port (although at the latter it has no effect). This allows you to restart a computation following an Exit port, which you first leapt over, but because of its unexpected failure you arrived at the Redo port. When you supply an integer argument, then this should denote an exact invocation number of an exited invocation present in the backtrace, and then the system will get you to the specified Exit port. The debugger requires here an exact invocation number so that it does not jump too far back in the execution (if an Exit port is not present in the backtrace, it may be be a better choice to jump to the preceding Call port, rather than to continue looking for another Exit port).

The jr jump to Redo port command transfers control back to the Redo port of the box. It can be used at an Exit or a Redo port (although at the latter it has no effect). This allows you to force the goal in question to try to deliver another solution. When you supply an integer argument, then this should denote an exact invocation number of an exited invocation present in the backtrace, and then the system will get you to the specified Redo port.

d
display goal displays the current goal using display/1. See Write (below).
p
print goal re-prints the current goal. An argument will override the default printdepth, treating 0 as infinity.
w
write goal writes the current goal using write/1.
g
print ancestor goals provides you with a list of ancestors to the current goal, i.e. all goals that are hierarchically above the current goal in the calling sequence. You can always be sure of jumping to the Call or Fail port of any goal in the ancestor list (by using retry etc). If you supply an integer n, then only that number of ancestors will be printed. That is to say, the last n ancestors will be printed counting back from the current goal. Each entry is displayed just as they would be in a trace message.
t
print backtrace is the same as the above, but also shows any goals that have exited non-deterministically and their ancestors. This information shows where there are outstanding choices that the program could backtrack to. If you supply an integer n, then only that number of goals will be printed.

Ancestors to the current goal are annotated with the Call: port, as they have not yet exited, whereas goals that have exited are annotated with the Exit: port. You can always be sure of jumping to the Exit or Redo port of any goal shown to be exited in the backtrace listing.

The backtrace is a tree rather than a stack: to find the parent of a given goal with depth indicator d, look for the closest goal above it with depth indicator d-1.

&
print blocked goals prints a list of the goals which are currently blocked in the current debugging session together with the variable that each such goal is blocked on (see Procedural). The goals are enumerated from 1 and up. If you supply an integer n, then only that goal will be printed. Each entry is preceded by the goal number followed by the variable name.
n
nodebug switches the debugger off. Note that this is the correct way to switch debugging off at a trace point. You cannot use the @ or b commands because they always return to the debugger.
=
debugging outputs information concerning the status of the debugging package. See Debug Pred, the built-in debugging/0.
+
spy this sets a plain spypoint on the current goal.
*
spy this conditionally sets a conditional spypoint on the current goal. Prompts for the Conditions, and issues a
spy(Func, Conditions)
command, where Func is the functor of the current invocation.
-
nospy this removes all spypoints applicable to the current goal. Equivalent to nospy Func, where Func is the functor of the current invocation.
\
remove this removes the spypoint which caused the debugger to interact at the current port. With an argument n, it removes the breakpoint with identifier n. Equivalent to remove_breakpoints(BID), where BID is the current breakpoint identifier, or the supplied argument.
D
disable this disables the spypoint which caused the debugger to interact at the current port. With an argument n, it disables the breakpoint with identifier n. Equivalent to disable_breakpoints(BID), where BID is the current breakpoint identifier, or the supplied argument.
E
enable this enables all specific spypoints for the predicate at the current port. With an argument n, it enables the breakpoint with identifier n.
.
find this outputs information about where the predicate being called is defined.
a
abort causes an abort of the current execution. All the execution states built so far are destroyed and you are put right back at the top-level. (This is the same as the built-in predicate abort/0.)
b
break calls the built-in predicate break/0, thus putting you at a recursive top-level with the execution so far sitting underneath you. When you end the break (^D) you will be reprompted at the port at which you broke. The new execution is completely separate from the suspended one; the invocation numbers will start again from 1 during the break. The debugger is temporarily switched off as you call the break and will be re-switched on when you finish the break and go back to the old execution. However, any changes to the leashing or to spypoints will remain in effect.
@
command gives you the ability to call arbitrary Prolog goals. It is effectively a one-off break (see above). The initial message | :- will be output on the standard error stream, and a command is then read from the standard input stream and executed as if you were at top level.
u
unify is available at the Call port and gives you the option of providing a solution to the goal from the standard input stream rather than executing the goal. This is convenient e.g. for providing a "stub" for a predicate that has not yet been written. A prompt will be output on the standard error stream, and the solution is then read from the standard input stream and unified with the goal. If the term read in is of the form Head :- Body, then Head will be unified with the current goal, and Body will be executed in its place.
e
raise exception is available at all ports. A prompt will be output on the standard error stream, and an exception term is then read from the standard input stream and raised in the program being debugged.
<
This command, without arguments, resets the printdepth to 10. With an argument of n, the printdepth is set to n, treating 0 as infinity.
^
While at a particular port, a current subterm of the current goal is maintained. It is the current subterm which is displayed, printed, or written when prompting for a debugger command. Used in combination with the printdepth, this provides a means for navigating in the current goal for focusing on the part which is of interest. The current subterm is set to the current goal when arriving at a new port. This command, without arguments, resets the current subterm to the current goal. With an argument of n (> 0), the current subterm is replaced by its n:th subterm. With an argument of 0, the current subterm is replaced by its parent term. With a list of arguments, the arguments are applied from left to right.
?
h
help displays the table of commands given above.

The following hook predicate can be used to customize the behavior of the interactive debugger.

debugger_command_hook(+Char,?Actions) [Hook]
user:debugger_command_hook(+Char,?Actions)

This predicate is called each time the debugger has read the first character Char of a debugger command. If it succeeds, Actions is taken as the list of actions (see Action Conditions) to be done for the given debugger command. If it fails, further arguments are read in, and the debugger command is interpreted in the standard way.

The above hook makes it possible to extend the interactive debugger with user-defined commands. The following example defines the S interactive debugger command to behave as skip at Call and Redo ports, and as creep otherwise:

debugger_command_hook(0'S, Actions) :-
        ttyskip(0'\n),        % skip till end of line
        execution_state([port(P),inv(I)]),
        Actions = [Mode,proceed,silent],
        (   P = call -> Mode = skip(I)
        ;   P = redo -> Mode = skip(I)
        ;   Mode = trace
        ).

Note that the silent action is needed above, otherwise the debugger message will be printed a second time, before continuing the execution.


Node:Breakpoint Predicates, Next:, Previous:Debug Commands, Up:Debug Intro

Breakpoint Handling Predicates

This section describes the advanced built-in predicates for creating and removing breakpoints.

add_breakpoint(:Conditions, ?BID)

Adds a breakpoint with conditions Conditions, the breakpoint identifier assigned is unified with BID. Conditions is one of the following:

Tests-Actions
Tests
standing for Tests-[]
-Actions
standing for []-Actions

Here Tests and Actions are lists of Conditions or a single Condition, see Breakpoint Conditions.

The add_breakpoint/2 predicate performs some transformations on the Conditions before adding the breakpoint. The goal and pred conditions are extracted from both the test and the action part and their consistency is checked. A goal condition is then inserted as the first element of the tests list, encapsulating all supplied goal conditions as well as those pred conditions which can be transformed to a goal condition. Furthermore the debugger condition is removed, and the advice condition is moved to the second element of the tests list. Finally a pred condition is inserted in front of the remaining tests, in the rare cases when it can not be made part of the preceding goal test. The rest of the test part and the action part is the same as supplied, with the extracted conditions removed.

There can only be a single plain spypoint for each predicate. If a plain spypoint is added, and there is already a plain spypoint for the given functor, then:

  1. the old spypoint is deleted and a new added as the most recent breakpoint, if this change affects the breakpoint selection mechanism.
  2. otherwise the old spypoint is kept and enabled if needed.

spy(:PredSpec, :Conditions)

Adds a conditional spypoint with conditions [pred(Pred)|Conditions], for each predicate Pred designated by the generalized predicate spec PredSpec.

current_breakpoint(:Conditions, ?BID, ?Status, ?Kind)

There is a breakpoint with conditions Conditions, breakpoint identifier BID, status Status and kind Kind. Status is one of on or off, referring to enabled and disabled breakpoints. Kind is one of plain, conditional or generic. current_breakpoint/4 enumerates all breakpoints on backtracking.

The Conditions as returned by current_breakpoint/4 may not be exactly the same as supplied at the creation of the breakpoint, because of the transformations done at creation, see the description of add_breakpoint/2 above.

remove_breakpoints(+BIDs)
disable_breakpoints(+BIDs)
enable_breakpoints(+BIDs)

Removes, disables or enables the breakpoints with identifiers specified by BIDs. BIDs can be a number, a list of numbers or one of the atoms: all, debugger, advice. The atoms specify all breakpoints, debugger type breakpoints and advice type breakpoints respectively.

execution_state(:Tests)

Tests are satisfied in the current state of the execution.

execution_state(+FocusConditions, :Tests)

Tests are satisfied in the state of the execution pointed to by FocusConditions.

Note that the built-in predicate arguments holding breakpoint conditions (Conditions or Tests above) are subject to module name expansion. The primitive conditions goal(_), pred(_), ancestor(_), and true(_) will inherit the module name from the (module name expanded) conditions argument, in the absence of explicit module qualification within the primitive condition.


Node:Breakpoint Processing, Next:, Previous:Breakpoint Predicates, Up:Debug Intro

The Processing of Breakpoints

This section describes in detail how the debugger handles the breakpoints. For the purpose of this section disabled breakpoints are not taken into account: whenever we refer to the existence of some breakpoint(s), we always mean the existence of enabled breakpoint(s).

The Prolog engine can be in one of the following three states with respect to the debugger:

no debugging
if there are no advice-points and the debugger is either switched off, or doing a skip;
full debugging
if the debugger is in trace or debug mode (creeping or leaping), or there are any generic breakpoints;
selective debugging
in all other cases.

In the selective debugging state only those predicate invocations are examined, for which there exists a specific breakpoint. In the full debugging state all invocations are examined, except those calling a non-exported predicate of a hidden module (but even these will be examined, if there is a specific breakpoint for them). In the no debugging state the debugger is not entered at predicate invocations.

Now we describe what the debugger does when examining an invocation of a predicate, i.e. executing its Call port.

First the debugger tries to select an applicable advice-point. It does this by considering all advice-points, most recent first, and evaluating the conditions in its tests and actions, in the order as stored by add_breakpoint/2; see Breakpoint Predicates. The first advice-point, for which this process succeeds, is selected. If there was no advice-point selected, or the variable command (initialized to proceed) was re-set to flit in the course of the selection process, then the debugger notes that the advice facility does not require the creation of a procedure box.

Second, the search for spypoints takes place. This is started by initializing the debugger action variables. The mode variable is set to the current debugger mode. The values for show and command depend on the hiddenness of the predicate being invoked, the debugger mode and the leashing status of the port. If the predicate is both defined in, and called from a hidden module, then the defaults will be silent and flit. An example of this is when a built-in predicate is called from a hidden module, e.g. from a library. Otherwise, in trace mode, the default values are print and ask for leashed ports, and print and proceed for unleashed ports. In debug mode, the variables default to silent and proceed, while in zip mode to silent and flit. These default values reflect the behaviour expected for the given debugger mode, e.g. in zip mode the debugger does not print debugging information and does not build procedure boxes.

Having initialized the debugger action variables, the system does the spypoint search, unless the debugger mode is off or skip. Finding an applicable spypoint is done in the same way as described for advice points. The only difference is that, when the test part of a spypoint succeeds and there is no action part, the [print,ask] actions are executed.

The third stage is the interactive part. First, the goal in question is displayed according to the value of show. Next, the value of command is checked: if it is other than ask the interactive stage ends. Otherwise, if it is ask, the debugger prompts the user for a command which is interpreted either in the standard way, or through user:debugger_command_hook/2. In both cases the debugger action variables are modified as requested, and the interactive part is repeated.

After the debugger went through all the three stages, it decides whether to build a procedure box. This will happen if either the advice-point stage or the other two stages require it. The latter is decided by checking the functor of command: if that is flit, then no procedure box is required by the spypoint part. In such a case, if the advice-point does require the building of a procedure box, the command variable is modified, by changing its functor to proceed.

At the end of the process the value of mode will be the new debugging mode, and command will determine what the debugger will do; see Action Variables.

A similar three-stage process is carried out when the debugger arrives at a non-Call port of a predicate. The only difference is that the building of a procedure box is not considered (flit is equivalent to proceed), and the hiddenness of the predicate is not taken into account.

While the Prolog system is executing the above three-stage process for any of the ports, it is said to be inside the debugger. This is relevant, because some of the conditions can only be evaluated in this context.


Node:Breakpoint Conditions, Next:, Previous:Breakpoint Processing, Up:Debug Intro

Breakpoint Conditions

This section describes the format of primitive breakpoint conditions. We first list the tests that can be used to enquire the state of execution. We then proceed to describe the conditions usable in the actions part and the options for focusing on past execution states. Finally we describe some simple condition macros and the valid values for the debugger action variables.

Unless noted otherwise, the tests are usable both inside the debugger, and outside it. Most of the tests can also be used in queries about past execution states, in execution_state/2. For the latter type of usage, in the following descriptions the term current should be interpreted as referring to the execution state focused on.

The test will fail if the given query is not meaningful in the given context, e.g. if execution_state(goal(G)) is queried before any breakpoints were encountered.


Node:Goal Tests, Next:, Previous:Breakpoint Conditions, Up:Breakpoint Conditions

Tests Related to the Current Goal

The following tests give access to basic information about the current invocation.

inv(Inv)
The invocation number of the current goal is Inv.
depth(Depth)
The current execution depth is Depth.
goal(MGoal)
The module name expanded MGoal template matches the current goal. The unification required for matching is carried out.
pred(MFunc)
The module name expanded MFunc template matches the functor (M:F/N) of the current goal. The unification required for matching is carried out.
module(Module)
The module of the current goal is Module.
goal_private(GoalPriv)
The private information associated with the current goal is GoalPriv.
last_port(LastPort)
LastPort is the last completed port of the invocation present on the backtrace. Practically, this is only useful when looking at past execution states. LastPort will be exit(nondet) if the invocation has been exited, and call otherwise.
parent_inv(Inv)
The invocation number of the debugger-parent of the current goal is Inv.
ancestor(AncGoal,Inv)
The youngest debugger-ancestor of the current goal, which matches the module name expanded AncGoal template, is at invocation number Inv. The unification required for matching is carried out.

Notes:

The debugger-parent of a goal is the youngest ancestor of the goal present on the backtrace. This will differ from the ordinary parent if not all goals are traced, e.g. if the goal in question is reached in zip mode. A debugger-ancestor of a goal is any of its ancestors on the backtrace.

In the goal and ancestor tests above, there is a given module qualified goal template, say ModT:GoalT, and it is matched against a concrete goal term Mod:Goal in the execution state. This matching is carried out as follows:

  1. For the match to succeed, Goal and GoalT have to be unifiable and are unified.
  2. Mod and ModT are either unifiable (and are unified), or name such modules in which Goal has the same meaning, i.e. either one of Mod:Goal and ModT:Goal is an exported variant of the other, or both are imported from the same module.

The above matching rules also apply for predicate functors, in the pred condition.


Node:Source Tests, Next:, Previous:Goal Tests, Up:Breakpoint Conditions

Tests Related to Source Information

These tests provide access to source related information. The file and line tests will fail if no source information is present. The parent_clause and parent_pred tests are available for interpreted code only.

file(File)
The current goal is invoked from file File.
line(File,Line)
The current goal is invoked from file File, line Line.
line(Line)
The current goal is invoked from line Line.
parent_clause(Cl)
The current goal is invoked from clause Cl.
parent_clause(Cl,Sel)
The current goal is invoked from clause Cl and within its body it is pointed to by the subterm selector Sel.
parent_clause(Cl,Sel,I)
The current goal is invoked from clause Cl, it is pointed to by the subterm selector Sel within its body, and it is the Ith goal within it. The goals in the body are counted following their textual occurrence.
parent_pred(Pred)
The current goal is invoked from predicate Pred.
parent_pred(Pred,N)
The current goal is invoked from predicate Pred, clause number N.


Node:Break Tests, Next:, Previous:Source Tests, Up:Breakpoint Conditions

Tests Related to the Break Level

These tests can be used both inside and outside the condition evaluation process, and also can be used in queries about past break levels.

break_level(N)
We are at (or focused on) break level N (N = 0 for the outermost break level).
max_inv(MaxInv)
The last invocation number in use within the break level is MaxInv.
private(Priv)
The private information associated with the break level is Priv. Similarly to goal_private/1, this condition refers initially to an uninstantiated variable and can be used to store an arbitrary Prolog term.


Node:Port Tests, Next:, Previous:Break Tests, Up:Breakpoint Conditions

Tests Related to the Current Port

These tests can only be used inside the debugger and only when focused on the current invocation. If they appear in execution_state/2 or in execution_state/1 called outside the debugger, an exception will be raised.

The notion of port in breakpoint handling is more general than outlined earlier in Procedure Box. Here the following terms are used to describe a port:

call, exit(nondet), exit(det), redo, fail,
exception(Exception), block, unblock

Furthermore, the atoms exit and exception can be used in the port condition (see below), to denote any of the two exit ports and an arbitrary exception port, respectively.

port(Port)
The current execution port matches Port in the following sense: either Port and the current port unify, or Port is the functor of the current port (e.g. port(exit) holds for both exit(det) and exit(nondet) ports).
bid(BID)
The breakpoint being examined has a breakpoint identifier BID. (BID = none if no breakpoint was selected.)
mode(Mode)
The debugger mode is Mode.
command(Command)
Command is the command to be executed if the breakpoint is selected.
show(Show)
The current show method (the goal display method) is Show.

The last three of the above tests access the debugger action variables. For example, the condition mode(trace), if it occurs in the tests, checks if the current debugger mode is trace. On the other hand, if the same term occurs within the action part, it sets the debugger mode to trace.

For the port, mode, command and show conditions, the condition can be replaced by its argument, if that is not a variable. For example the condition call can be used instead of port(call). Conditions matching the templates listed above as valid port values will be converted to a port condition. Similarly, any valid value for the three debugger action variables is converted to an appropriate condition. These valid values are described below; see Action Variables.


Node:Other Tests, Next:, Previous:Port Tests, Up:Breakpoint Conditions

Other Conditions

The following conditions are for prescribing or checking the breakpoint type. They are only meaningful inside the debugger and only for the current invocation.

advice
The breakpoint in question is of advice type.
debugger
The breakpoint in question is of debugger type.

The following construct converts an arbitrary Prolog goal into a condition.

true(Cond)
The Prolog goal Cond is true, (Cond is executed and the condition is satisfied iff the goal completes successfully). The substitutions done on executing Cond are carried out. Cond is subject to module name expansion. If used in the test part of spypoint conditions, the goal should not have any side effects, as the test part may be evaluated several times.


Node:Action Conditions, Next:, Previous:Other Tests, Up:Breakpoint Conditions

Conditions Usable in the Action Part

mode(Mode)
Set the debugger mode to Mode.
command(Command)
Set the command to be executed to Command.
show(Show)
Set the show method to Show.

The values admissible for Mode, Command and Show are described below; see Action Variables.

Furthermore, any other condition can be used in the action part, except for the ones specifying the type (advice or debugger).


Node:Past States, Next:, Previous:Action Conditions, Up:Breakpoint Conditions

Options for Focusing on a Past State

The following terms can be used in the first argument of execution_state/2 (see Breakpoint Predicates).

break_level(I)
Focus on the current invocation of break level I.
inv(Inv)
Focus on the invocation number Inv of the currently focused break level.


Node:Condition Macros, Next:, Previous:Past States, Up:Breakpoint Conditions

Condition Macros

There are a few condition macros expanding to a list of other conditions:

unleash
Expands to [show(print),command(proceed)]
hide
Expands to [show(silent),command(proceed)]
leash
Expands to [show(print),command(ask)]


Node:Action Variables, Previous:Condition Macros, Up:Breakpoint Conditions

The Action Variables

We first list the possible values of the debugger action variables, and their meaning. We then discuss how these variables are initialized and changed.

Values allowed in the show condition:

print
Write using options stored in the debugger_print_options Prolog flag.
silent
Display nothing.
display
Write using display.
write
Write using writeq.
write_term(Options)
Write using options Options.
Method-Sel
Display only the subterm selected by Sel, using Method. Here Method is one of the methods above, and Sel is a subterm selector.

Values allowed in the command condition:

ask
Ask the user what to do next.
proceed
Continue the execution without interacting with the user (cf. unleashing).
flit
Continue the execution without building a procedure box for the current goal (and consequently not encountering any other ports for this invocation). Only meaningful at call ports, at other ports it is equivalent to proceed.
proceed(Goal,New)
Unify the current goal with Goal and execute the goal New in its place. Goal and New are module name expanded only at execution time with the current type-in module as the default. Only available at call ports. This construct is used by the u (unify) interactive debugger command.
flit(Goal,New)
Unify the current goal with Goal and execute the goal New in its place, without creating a procedure box for Goal (and consequently not encountering any other ports for this invocation). Only available at call ports. Also see note on module name expansion for proceed/2.
exception(E)
Raise the exception E.
abort
Abort the execution.
retry(Inv)
Retry the the most recent goal with an invocation number less or equal to Inv (go back to the call port of the goal). This is used by the interactive debugger command r, retry; see Debug Commands.
reexit(Inv)
Re-exit the the invocation with number Inv (go back to the exit port of the goal). Inv must be an exact reference to an exited invocation present in the backtrace (exited nondeterministically, or currently being exited). This is used by the interactive debugger command je, jump to exit port; see Debug Commands.
redo(Inv)
Redo the the invocation with number Inv (go back to the redo port of the goal). Inv must be an exact reference to an exited invocation present in the backtrace. This is used by the interactive debugger command jr, jump to redo port; see Debug Commands.
fail(Inv)
Fail the the most recent goal with an invocation number less or equal to Inv (transfer control back to the fail port of the goal). This is used by the interactive debugger command f, fail; see Debug Commands.

Values allowed in the mode condition:

qskip(Inv)
Quasi-skip until the first port with invocation number less or equal to Inv is reached. Valid only if Inv >= 1 and furthermore Inv =< CurrInv for entry ports (call, redo), and Inv < CurrInv for all other ports, where CurrInv is the invocation number of the current port.
skip(Inv)
Skip until the first port with invocation number less or equal to Inv is reached. Inv should obey the same rules as for qskip.
trace
Creep.
debug
Leap.
zip
Zip.
off
Continue without debugging.


Node:Consult, Next:, Previous:Breakpoint Conditions, Up:Debug Intro

Consulting during Debugging

It is possible, and sometimes useful, to consult a file whilst in the middle of program execution. Predicates, which have been successfully executed and are subsequently redefined by a consult and are later reactivated by backtracking, will not notice the change of their definitions. In other words, it is as if every predicate, when called, creates a virtual copy of its definition for backtracking purposes.

If SICStus Prolog is run via the Emacs interface, the commands for loading code (such as C-c C-p, consulting the current predicate) are not directly available when the system prompts you after printing out a debugging message. Press b followed by <RET> to get a recursive top-level, ready to accept the Emacs commands. Type ^D to return to the debugging port.


Node:Exceptions Debug, Next:, Previous:Consult, Up:Debug Intro

Catching Exceptions

Usually, exceptions that occur during debugging sessions are displayed only in trace mode and for invocation boxes for predicates with spypoints on them, and not during skips. However, it is sometimes useful to make exceptions trap to the debugger at the earliest opportunity instead. The hook predicate user:error_exception/1 provides such a possibility:

error_exception(+Exception) [Hook]
user:error_exception(+Exception)

This predicate is called at all exception ports. If it succeeds, the debugger enters trace mode and prints an exception port message. Otherwise, the debugger mode is unchanged and a message is printed only in trace mode or if a spypoint is reached, and not during skips.


Node:Breakpoint Example, Previous:Exceptions Debug, Up:Debug Intro

Advanced Debugger Examples

We will show two examples using the advanced features of the debugger.

The first example defines a hide_exit(Pred) predicate, which will hide the exit port for Pred (i.e. it will silently proceed), provided the current goal was already ground at the call port, and nothing was traced inside the given invocation. The hide_exit(Pred) creates two spypoints for predicate Pred:

:- meta_predicate hide_exit(:).
hide_exit(Pred) :-
        add_breakpoint([pred(Pred),call]-
                         true(save_groundness), _),
        add_breakpoint([pred(Pred),exit,true(hide_exit)]-hide, _).

The first spypoint is applicable at the call port, and it calls save_groundness to check if the given invocation was ground, and if so, it sets the goal_private attribute of the invocation to ground.

save_groundness :-
        execution_state([goal(_:G),goal_private(Priv)]),
        ground(G), !, Priv = ground.
save_groundness.

The second spypoint created by hide_exit is applicable at the exit port and it checks whether the hide_exit condition is true. If so, it issues a hide action, which is an abbreviation of [show(silent),command(proceed)].

hide_exit :-
        execution_state([inv(I),max_inv(I),goal_private(Priv)]),
        Priv == ground.

Here hide_exit encapsulates the tests that the invocation number is the same as the last invocation number used (max_inv), and that the goal_private attribute of the invocation is identical to ground. The first test ensures that nothing was traced inside the current invocation.

If we load the above code, as well as the small example below, then the following interaction can take place. Note that the hide_exit is called with the _:_ argument, resulting in generic spypoints being created.

| ?- [user].
| cnt(0) :- !.
| cnt(N) :-
|       N > 0, N1 is N-1, cnt(N1).
| {user consulted, 0 msec 424 bytes}

yes
| ?- hide_exit(_:_), trace, cnt(1).
{The debugger will first zip -- showing spypoints (zip)}
{Generic spypoint added, BID=1}
{Generic spypoint added, BID=2}
{The debugger will first creep -- showing everything (trace)}
 #      1      1 Call: cnt(1) ?
 #      2      2 Call: 1>0 ?
 #      3      2 Call: _2019 is 1-1 ?
        3      2 Exit: 0 is 1-1 ?
 #      4      2 Call: cnt(0) ?
        1      1 Exit: cnt(1) ?

yes
{trace}
| ?-

Our second example defines a predicate call_backtrace(Goal, BTrace), which will execute Goal and build a backtrace showing the successful invocations executed during the solution of Goal.

The advantages of such a special backtrace over the one incorporated in the debugger are the following:

The call_backtrace predicate is based on the advice facility. It uses the variable accessible via the private(_) condition to store a mutable holding the backtrace. Outside the call_backtrace predicate the mutable will have the value off.

The example is a module-file, so that internal invocations can be identified by the module-name.

:- module(backtrace, [call_backtrace/2]).

call_backtrace/2 is a meta-predicate, which first sets up an appropriate advice-point for building the backtrace. This step is skipped if there already exists a breakpoint of this kind. Note the careful formulation of the breakpoint condition Cond: a fully spelled out form is used (e.g. port(call) instead of call), so that Cond is good both for checking the presence of a breakpoint with the given conditions in current_breakpoint/4, and for creating a new breakpoint in add_breakpoint/2.

Having ensured the appropriate advice-point exists, call_backtrace/2 picks up the private field of the execution state and calls call_backtrace/3 with a cleanup operation ensuring that the breakpoint added is removed at the end.

:- meta_predicate call_backtrace(:, ?).
call_backtrace(Goal, BTrace) :-
        Cond = [goal(M:G),advice,port(call),private(Priv),
                true(backtrace:store_goal(M,G,Priv))]
                  -[command(flit)],
        (   current_breakpoint(Cond, _, on, _) -> B = []
        ;   add_breakpoint(Cond, B)
        ),
        execution_state(private(Priv)),
        call_cleanup(call_backtrace(Goal, BTrace, Priv),
                     remove_breakpoints(B)).

The predicate call_backtrace/3 receives the private field of the execution state in its Priv argument. It assumes that this is either a mutable or a yet uninstantiated variable. In the latter case the variable is set to a newly created mutable. In both cases the mutable is initialized to [], and the Goal is called. In the course of the execution of the Goal the debugger will accumulate the backtrace in the mutable. Finally, the mutable is read, its value returned in BTrace and it is restored to its old value (or off).

:- meta_predicate call_backtrace(:, ?, ?).
call_backtrace(Goal, BTrace, Priv) :-
        (   is_mutable(Priv) -> get_mutable(Old, Priv),
            update_mutable([], Priv)
        ;   create_mutable([], Priv), Old = off
        ),
        call(Goal),
        get_mutable(BTrace, Priv), update_mutable(Old, Priv).

store_goal/3 is the predicate called by the advice-point, with the module, the goal and the private mutable as arguments. The first clause ensures that calls from within the backtrace module get ignored. The second clause prepends the module qualified goal term to the private mutable, provided the latter exists and its value is not off.

store_goal(backtrace, _, _) :- !, fail.
store_goal(M, G, Priv) :-
        is_mutable(Priv),
        get_mutable(BTrace, Priv),
        BTrace \== off,
        update_mutable([M:G|BTrace], Priv).

Below is an example run, using a small program:

| ?- [user].
| cnt(N):- N =< 0, !.
| cnt(N) :-
     N > 0, N1 is N-1, cnt(N1).
| {consulted user in module user, 0 msec 224 bytes}

yes
| ?- call_backtrace(cnt(1), B).
{Generic advice point added, BID=1}
{Generic advice point, BID=1, removed (last)}

B = [user:(0=<0),user:cnt(0),user:(0 is 1-1),user:(1>0),user:cnt(1)] ?

yes
| ?-


Node:Built Intro, Next:, Previous:Debug Intro, Up:Top

Built-In Predicates

It is not possible to redefine built-in predicates. An attempt to do so will give an error message. See Pred Summary.

SICStus Prolog provides a wide range of built-in predicates to perform the following tasks:

Input / Output
     Reading-in Programs
     Term and Goal Expansion
     Input and Output of Terms
     Character I/O
     Stream I/O
     Dec-10 Prolog File I/O
Arithmetic
Comparison of Terms
Control
Error and Exception Handling
Information about the State of the Program
Meta-Logic
Modification of Terms
Modification of the Program
Internal Database
Blackboard Primitives
All Solutions
Coroutining
Debugging
Execution Profiling
Miscellaneous

When introducing a built-in predicate, we shall present its usage with a mode spec, and optionally with an annotation containing one or more of:

ISO
The predicate complies with the ISO Prolog Standard.
ISO only
The predicate variant described complies with the ISO Prolog Standard and is valid in the iso execution mode only.
SICStus only
The predicate variant described is valid in the sicstus execution mode only.
declaration
A declaration that can't be redefined as a predicate.
hook
The predicate is a hook predicate.
hookable
The predicate is a hookable predicate.
obsolescent
The predicate is obsolescent and should be avoided in new code.
reserved
A reserved construct that can't be defined as a predicate.

The following descriptions of the built-in predicates are grouped according to the above categorization of their tasks.


Node:Input Output, Next:, Previous:Built Intro, Up:Built Intro

Input / Output

There are two sets of file manipulation predicates in SICStus Prolog. One set is inherited from DEC-10 Prolog. These predicates always refer to a file by name. The other set of predicates is modeled after Quintus Prolog and refer to files as streams. Streams correspond to the file pointers used at the operating system level.

This second set of file manipulation predicates, the one involving streams, is supported by the ISO Prolog standard. Note that the notion of file is used here in a generalized sense; it may refer to a name file, the user's terminal, or some other device. The ISO Prolog standard refers to this generalized notion of file using the term source/sink.

A stream can be opened and connected to a filename or file descriptor for input or output by calling the predicates open/[3,4]. These predicates will return a reference to a stream which may then be passed as an argument to various I/O predicates. Alternatively, a stream can be assigned an alias at the time of opening, and referred to by this alias afterwards. The predicate close/1 is used for closing a stream.

There are two types of streams, binary or text. Binary streams are seen as a sequence of bytes, i.e. integers in the range 0-255. Text streams, on the other hand, are considered a sequence of characters, represented by their character codes. SICStus Prolog handles wide characters, i.e. characters with codes larger than 255. The WCX (Wide Character eXtension) component of SICStus Prolog allows selecting various encoding schemes via environment variables or hook procedures; see Handling Wide Characters.

The predicates current_stream/3 and stream_property/2 are used for retrieving information about a stream, and for finding the currently existing streams.

Prolog streams can be accessed from C functions as well. See SICStus Streams, for details.

The possible formats of a stream are:

'$stream'(X)
A stream connected to some file. X is an integer.
Atom
A stream alias. Aliases can be associated with streams using the alias(Atom) option of open/4. There are also three predefined aliases:

user_input
An alias initially referring to the UNIX stdin stream. The alias can be changed with prolog_flag/3 and accessed by the C variable SP_stdin.
user_output
An alias initially referring to the UNIX stdout stream. The alias can be changed with prolog_flag/3 and accessed by the C variable SP_stdout.
user_error
An alias initially referring to the UNIX stderr stream. The alias can be changed with prolog_flag/3 and accessed by the C variable SP_stderr.

This stream is used by the Prolog top level and debugger, and for system messages.

Certain I/O predicates manipulate streams implicitly, by maintaining the notion of a current input stream and a current output stream. The current input and output streams are set to the user_input and user_output initially and for every new break (see Nested). The predicate see/1 (tell/1) can be used for setting the current input (output) stream to newly opened streams for particular files. The predicate seen/0 (told/0) closes the current input (output) stream, and resets it to the standard input (output) stream. The predicate seeing/1 (telling/1) is used for retrieving the filename associated with the current input (output) streams.

The possible formats of a filename are:

The filename user stands for the standard input or output stream, depending on context. Terminal output is only guaranteed to be displayed if the output stream is explicitly flushed.

A filename other than user must be an atom or a compound term. It is subject to four phases of rewriting:

  1. Rewriting to an atomic filename (see below).
  2. Expansion of any leading ~ or $ (see below).
  3. If the filename is still not absolute, the name of the current working directory is prepended. Note that while loading code, the current working directory is temporarily changed to the directory containing the file being read in.
  4. An optional extension is added, depending on the operation to be performed on the file.

General filenames are rewritten to atomic filenames as follows:

Once an atomic filename has been obtained, it is subject to another rewriting step if it begins with ~ or $. For example,


~/sample.pl
is equivalent to /home/sics/al/sample.pl, if /home/sics/al is the user's home directory. (This is also equivalent to $HOME/sample.pl as explained below.)
~clyde/sample.pl
is equivalent to /home/sics/clyde/sample.pl, if /home/sics/clyde is Clyde's home directory.
$UTIL/sample.pl
is equivalent to /usr/local/src/utilities/sample.pl, provided the value of the environment variable UTIL is /usr/local/src/utilities.

For example, given the clauses:

file_search_path(home, '$HOME').
file_search_path(demo, home(prolog(demo))).
file_search_path(prolog, prolog).

the filename demo(mydemo) would be rewritten to '$HOME/prolog/demo/mydemo', where '$HOME' is interpreted as an environment variable (the user's home directory).

Failure to open a file normally causes an exception to be raised. This behavior can be turned off and on by of the built-in predicates nofileerrors/0 and fileerrors/0 described below.


Node:Read In, Next:, Previous:Input Output, Up:Input Output

Reading-in Programs

When the predicates discussed in this section are invoked, filenames are relative to the current working directory. During the load, the current working directory is temporarily changed to the directory containing the file being read in. This has the effect that if one of these predicates is invoked recursively, the filename of the recursive load is relative to the directory of the enclosing load. See Load Intro, for an introduction to these predicates.

Directives will be executed in order of occurrence. Be aware of the changed current working directory as it could have an effect on the semantics of directives. Only the first solution of directives is produced, and variable bindings are not displayed. Directives that fail or raise exceptions give rise to warning or error messages, but do not terminate the load. However, these warning or error messages can be intercepted by the hook user:portray_message/2 which can call abort/0 to terminate the load, if that is the desired behavior.

Predicates loading source code are affected by the character-conversion mapping, cf. char_conversion/2; see Term I/O.

Most of the predicates listed below take an argument Files which is a single file name or a list of file names. Source, object and QL files usually end with a .pl, .po and .ql suffix respectively. These suffixes are optional. Each file name may optionally be prefixed by a module name. The module name specifies where to import the exported predicates of a module-file, or where to store the predicates of a non-module-file. The module is created if it doesn't exist already.

absolute_file_name/2 (see Stream Pred) is used to look up the files. The file name user is reserved and denotes the standard input stream.

These predicates are available in runtime systems with the following limitations:


load_files(:Files)
load_files(:Files, +Options)

A generic predicate for loading files with a list of options to provide extra control. This predicate in fact subsumes the other predicates except use_module/3 which also returns the name of the loaded module, or imports a set of predicates from an existing module. Options is a list of zero or more of the following:

if(X)
true (the default) to always load, or changed to load only if the file has not yet been loaded or if it has been modified since it was last loaded. A non-module-file is not considered to have been previously loaded if it was loaded into a different module. The file user is never considered to have been previously loaded.
when(When)
always (the default) to always load, or compile_time to load only if the goal is not in the scope of another load_files/[1,2] directive occurring in a .po or .ql file.

The latter is intended for use when the file only defines predicates that are needed for proper term or goal expansion during compilation of other files.

load_type(LoadType)
source to load source files only, object to load object (.po) files only, ql (obsolescent) to load .ql files only, or latest (the default) to load any type of file, whichever is newest. If the file is user, source is forced.
imports(Imports)
all (the default) to import all exported predicates if the file is a module-file, or a list of predicates to import.
compilation_mode(Mode)
compile to translate into compiled code, consult to translate into static, interpreted code, or assert_all to translate into dynamic, interpreted code.

The default is the compilation mode of any ancestor load_files/[1,2] goal, or compile otherwise. Note that Mode has no effect when an .po or .ql file is loaded, and that it is recommended to use assert_all in conjunction with load_type(source), to ensure that the source file will be loaded even in the presence of a .po or .ql file.

wcx(Wcx)
To pass the term Wcx to the wide character extension component; see Prolog Level WCX Features.

consult(:Files)
reconsult(:Files) [Obsolescent]
[]
[:File|+Files]

Consults the source file or list of files specified by File and Files. Same as load_files(Files, [load_type(source),compilation_mode(consult)]).

compile(:Files)

Compiles the source file or list of files specified by Files. The compiled code is placed in-core, i.e. is added incrementally to the Prolog database. Same as load_files(Files, [load_type(source),compilation_mode(compile)]).

load(:Files) [Obsolescent]

Loads the .ql file or list of files specified by Files. Same as load_files(Files, [load_type(ql)]).

ensure_loaded(:Files) [ISO]

Compiles or loads the file or files specified by Files that have been modified after the file was last loaded, or that have not yet been loaded. The recommended style is to use this predicate for non-module-files only, but if any module-files are encountered, their public predicates are imported. Same as load_files(Files, [if(changed)]).

use_module(:File)

Compiles or loads the module-file specified by File if it has been modified after it was last loaded, or not yet been loaded. Its public predicates are imported. The recommended style is to use this predicate for module-files only, but any non-module-files encountered are simply compiled or loaded. Same as load_files(File, [if(changed)]).

use_module(:File, +Imports)

Loads the module-file File like ensure_loaded/1 and imports the predicates in Imports. If any of these are not public, a warning is issued. Imports may also be set to the atom all in which case all public predicates are imported. Same as load_files(File, [if(changed),imports(Imports)]).

use_module(-Module, :File, +Imports)
use_module(+Module, :File, +Imports)

If used with +Module, and that module already exists, this merely imports Imports from that module. Otherwise, this is equivalent to use_module(File, Imports) with the addition that Module is unified with the loaded module.

fcompile(:Files) [Obsolescent]

Compiles the source file or list of files specified by Files. If Files are prefixed by a module name, that module name will be used for module name expansion during the compilation (see Considerations). The suffix .pl is added to the given filenames to yield the real source filenames. The compiled code is placed on the .ql file or list of files formed by adding the suffix .ql to the given filenames. (This predicate is not available in runtime systems.)

source_file(?File)

File is the absolute name of a source file currently in the system.

source_file(:Head,?File)
source_file(-Head,?File)

Head is the most general goal for a predicate loaded from File.

require(:PredSpecOrSpecs)

PredSpecOrSpecs is a predicate spec or a list or a conjunction of such. The predicate will check if the specified predicates are loaded and if not, will try to load or import them using use_module/2. The file containing the predicate definitions will be located in the following way:


Node:Definite, Next:, Previous:Read In, Up:Input Output

Term and Goal Expansion

When a program is being read in, SICStus Prolog provides hooks that enable the terms being read in to be source-to-source transformed before the usual processing of clauses or directives. The hooks consist in user-defined predicates that define the transformations. One transformation is always available, however: definite clause grammars, a convenient notation for expressing grammar rules. See [Colmerauer 75] and [Pereira & Warren 80].

Definite clause grammars are an extension of the well-known context-free grammars. A grammar rule in Prolog takes the general form

head --> body.

meaning "a possible form for head is body". Both body and head are sequences of one or more items linked by the standard Prolog conjunction operator ,.

Definite clause grammars extend context-free grammars in the following ways:

  1. A non-terminal symbol may be any Prolog term (other than a variable or number).
  2. A terminal symbol may be any Prolog term. To distinguish terminals from non-terminals, a sequence of one or more terminal symbols is written within a grammar rule as a Prolog list. An empty sequence is written as the empty list []. If the terminal symbols are character codes, such lists can be written (as elsewhere) as strings. An empty sequence is written as the empty list, [] or "".
  3. Extra conditions, in the form of Prolog procedure calls, may be included in the right-hand side of a grammar rule. Such procedure calls are written enclosed in {} brackets.
  4. The left-hand side of a grammar rule consists of a non-terminal, optionally followed by a sequence of terminals (again written as a Prolog list).
  5. Disjunction, if-then, if-then-else, and not-provable may be stated explicitly in the right-hand side of a grammar rule, using the operators ; (|), ->, and \+ as in a Prolog clause.
  6. The cut symbol may be included in the right-hand side of a grammar rule, as in a Prolog clause. The cut symbol does not need to be enclosed in {} brackets.

As an example, here is a simple grammar which parses an arithmetic expression (made up of digits and operators) and computes its value.

expr(Z) --> term(X), "+", expr(Y), {Z is X + Y}.
expr(Z) --> term(X), "-", expr(Y), {Z is X - Y}.
expr(X) --> term(X).

term(Z) --> number(X), "*", term(Y), {Z is X * Y}.
term(Z) --> number(X), "/", term(Y), {Z is X / Y}.
term(Z) --> number(Z).

number(C) --> "+", number(C).
number(C) --> "-", number(X), {C is -X}.
number(X) --> [C], {"0"=<C, C=<"9", X is C - "0"}.

In the last rule, C is the character code of some digit.

The query

| ?- expr(Z, "-2+3*5+1", []).

will compute Z=14. The two extra arguments are explained below.

Now, in fact, grammar rules are merely a convenient "syntactic sugar" for ordinary Prolog clauses. Each grammar rule takes an input string, analyses some initial portion, and produces the remaining portion (possibly enlarged) as output for further analysis. The arguments required for the input and output strings are not written explicitly in a grammar rule, but the syntax implicitly defines them. We now show how to translate grammar rules into ordinary clauses by making explicit the extra arguments.

A rule such as

p(X) --> q(X).

translates into

p(X, S0, S) :- q(X, S0, S).

If there is more than one non-terminal on the right-hand side, as in

p(X, Y) -->
        q(X),
        r(X, Y),
        s(Y).

then corresponding input and output arguments are identified, as in

p(X, Y, S0, S) :-
        q(X, S0, S1),
        r(X, Y, S1, S2),
        r(Y, S2, S).

Terminals are translated using the built-in predicate 'C'(S1, X, S2), read as "point S1 is connected by terminal X to point S2", and defined by the single clause

'C'([X|S], X, S).

(This predicate is not normally useful in itself; it has been given the name upper-case c simply to avoid using up a more useful name.) Then, for instance

p(X) --> [go,to], q(X), [stop].

is translated by

p(X, S0, S) :-
        'C'(S0, go, S1),
        'C'(S1, to, S2),
        q(X, S2, S3),
        'C'(S3, stop, S).

Extra conditions expressed as explicit procedure calls naturally translate as themselves, e.g.

p(X) --> [X], {integer(X), X>0}, q(X).

translates to

p(X, S0, S) :-
        'C'(S0, X, S1),
        integer(X),
        X>0,
        q(X, S1, S).

Similarly, a cut is translated literally.

Terminals are translated using the built-in predicate 'C'(S1, X, S2), read as "point S1 is connected by terminal X to point S2", and defined by the single clause

Terminals on the left-hand side of a rule are also translated using 'C'/3, connecting them to the output argument of the head non-terminal, e.g.

is(N), [not] --> [aint].

becomes

is(N, S0, S) :-
        'C'(S0, aint, S1),
        'C'(S, not, S1).

Disjunction has a fairly obvious translation, e.g.

args(X, Y) -->
        (   dir(X), [to], indir(Y)
        ;   indir(Y), dir(X)
        ).

translates to

args(X, Y, S0, S) :-
        (   dir(X, S0, S1),
            'C'(S1, to, S2),
            indir(Y, S2, S)
        ;   indir(Y, S0, S1),
            dir(X, S1, S)
        ).

Similarly for if-then, if-then-else, and not-provable.

The built-in predicates which are concerned with grammar rules and other compile/consult time transformations are as follows:


expand_term(+Term1,?Term2)

If Term1 is a term that can be transformed, Term2 is the result. Otherwise Term2 is just Term1 unchanged. This transformation takes place automatically when grammar rules are read in, but sometimes it is useful to be able to perform it explicitly. Grammar rule expansion is not the only transformation available; the user may define clauses for the predicate user:term_expansion/[2,4] to perform other transformations. user:term_expansion(Term1[,Layout1],Term2[,Layout2]) is called first, and only if it fails is the standard expansion used.

term_expansion(+Term1,?TermOrTerms) [Hook]
term_expansion(+Term1,+Layout1,?TermOrTerms,?Layout2) [Hook]
user:term_expansion(+Term1,?TermOrTerms)
user:term_expansion(+Term1,+Layout1,?TermOrTerms,?Layout2)

Defines transformations on terms read while a program is consulted or compiled. It is called for every Term1 read, including at end of file, represented as the term end_of_file. If it succeeds, TermOrTerms is used for further processing, otherwise the default grammar rule expansion is attempted. It is often useful to let a term expand to a list of directives and clauses, which will then be processed sequentially.

The 4 arguments version also defines transformations on the layout of the term read, so that the source-linked debugger can display accurate source code lines if the transformed code needs debugging. Layout1 is the layout corresponding to Term1, and Layout2 should be a valid layout of TermOrTerms (see Term I/O).

For accessing aspects of the load context, e.g. the name of the file being compiled, the predicate prolog_load_context/2 (see State Info) can be used.

user:term_expansion/[2,4] may also be used to transform queries entered at the terminal in response to the | ?- prompt. In this case, it will be called with Term1 = ?-(Query) and should succeed with TermOrTerms = ?-(ExpandedQuery).

goal_expansion(+Goal,+Module,?NewGoal) [Hook]
user:goal_expansion(+Goal,+Module,?NewGoal)

Defines transformations on goals while clauses are being consulted, compiled or asserted, after any processing by user:term_expansion/[2,4] of the terms being read in. It is called for every simple Goal encountered in the calling context Module. If it succeeds, Goal is replaced by NewGoal, otherwise Goal is left unchanged. NewGoal may be an arbitrarily complex goal, and user:goal_expansion/3 is recursively applied to its subgoals.

This predicate is also used to resolve meta-calls to Goal at runtime via the same mechanism. If the transformation succeeds, NewGoal is simply called instead of Goal. Otherwise, if Goal is a goal of an existing predicate, that predicate is invoked. Otherwise, error recovery is attempted by user:unknown_predicate_handler/3 as described below.

user:goal_expansion/3 can be regarded as a macro expansion facility. It is used for this purpose to support the interface to attributed variables in library(atts), which defines the predicates M:get_atts/2 and M:put_atts/2 to access module-specific variable attributes. These "predicates" are actually implemented via the user:goal_expansion/3 mechanism. This has the effect that calls to the interface predicates are expanded at compile time to efficient code.

For accessing aspects of the load context, e.g. the name of the file being compiled, the predicate prolog_load_context/2 (see State Info) can be used.

phrase(:Phrase,?List)
phrase(:Phrase,?List,+Remainder)

The list List is a phrase of type Phrase (according to the current grammar rules), where Phrase is either a non-terminal or more generally a grammar rule body. Remainder is what remains of the list after a phrase has been found. If called with 2 arguments, the remainder has to be the empty list.

'C'(?S1,?Terminal,?S2)

Not normally of direct use to the user, this built-in predicate is used in the expansion of grammar rules (see above). It is defined as if by the clause 'C'([X|S], X, S).


Node:Term I/O, Next:, Previous:Definite, Up:Input Output

Input and Output of Terms

Most of the following predicates come in two versions, with or without a stream argument. Predicates without a stream argument operate on the current input or output stream, depending on context. Predicates with a stream argument can take stream reference or an alias in this argument position, the alias being replaced by the stream it was associated with.

Some of these predicates support a notation for terms containing multiple occurrences of the same subterm (cycles and DAGs). The notation is @(Template,Substitution) where Substitution is a list of Var=Term pairs where the Var occurs in Template or in one of the Terms. This notation stands for the instance of Template obtained by binding each Var to its corresponding Term. The purpose of this notation is to provide a finite printed representation of cyclic terms. This notation is not used by default, and @/2 has no special meaning except in this context.

read(?Term) [ISO]
read(+Stream,?Term) [ISO]

The next term, delimited by a full-stop (i.e. a ., possibly followed by layout text), is read from Stream and is unified with Term. The syntax of the term must agree with current operator declarations. If a call read(Stream, Term) causes the end of Stream to be reached, Term is unified with the term end_of_file. Further calls to read/2 for the same stream will then raise an exception, unless the stream is connected to the terminal. The characters read are subject to character-conversion, see below.

read_term(?Term,+Options) [ISO]
read_term(+Stream,?Term,+Options) [ISO]

Same as read/[1,2] with a list of options to provide extra control or information about the term. Options is a list of zero or more of:

syntax_errors(+Val)
Controls what action to take on syntax errors. Val must be one of the values allowed for the syntax_errors Prolog flag. The default is set by that flag.
variables(?Vars)
Vars is bound to the list of variables in the term input, in left-to-right traversal order.
variable_names(?Names)
Names is bound to a list of Name=Var pairs, where each Name is an atom indicating the name of a non-anonymous variable in the term, and Var is the corresponding variable.
singletons(?Names)
Names is bound to a list of Name=Var pairs, one for each variable appearing only once in the term and whose name does not begin with _.
cycles(+Boolean)
Boolean must be true or false. If selected, any occurrences of @/2 in the term read in are replaced by the potentially cyclic terms they denote as described above. Otherwise (the default), Term is just unified with the term read in.
layout(?Layout)
Layout is bound to a layout term corresponding to Term. The layout Y of a term X is one of:
  • If X is a variable or atomic term, Y is the number of the line where X occurs.
  • If X is a compound term, Y is a list whose head is the number of the line where the first token of X occurs, and whose remaining elements are the layouts of the arguments of X.
  • [], if no line number information is available for X.
| ?- read_term(T, [layout(L), variable_names(Va), singletons(S)]).
|: [
     foo(X),
     X = Y
     ].

L = [35,[36,36],[36,[37,37,37],38]],
S = ['Y'=_A],
T = [foo(_B),_B=_A],
Va = ['X'=_B,'Y'=_A]

char_conversion(+InChar, +OutChar) [ISO]

InChar and OutChar should be one-char atoms. If they are not the same, then the mapping of InChar to OutChar is added to the character-conversion mapping. This means that in all subsequent term and program input operations any unquoted occurrence of InChar will be replaced by OutChar. The rationale for providing this facility is that in some extended character sets (such as Japanese JIS character sets) the same character can appear several times and thus have several codes, which the users normally expect to be equivalent. It is advisable to always quote the arguments of char_conversion/2.

If InChar and OutChar are the same, the effect of char_conversion/2 is to remove any mapping of InChar from the character-conversion mapping.

current_char_conversion(?InChar, ?OutChar) [ISO]

The character of one-char atom InChar is mapped to that of the one-char atom OutChar in the current character-conversion mapping. Enumerates all such pairs on backtracking.

write(?Term) [ISO]
write(+Stream,?Term) [ISO]

The term Term is written onto Stream according to current operator declarations. Same as write_term([Stream,] Term, [numbervars(true)]).

display(?Term)

The term Term is displayed onto the standard output stream (which is not necessarily the current output stream) in standard parenthesized prefix notation. Same as write_term(user, Term, [ignore_ops(true)]).

write_canonical(?Term) [ISO]
write_canonical(+Stream,?Term) [ISO]

Similar to write(Stream,Term). The term will be written according to the standard syntax. The output from write_canonical/2 can be parsed by read/2 even if the term contains special characters or if operator declarations have changed. Same as write_term([Stream,] Term, [quoted(true),ignore_ops(true)]).

writeq(?Term) [ISO]
writeq(+Stream,?Term) [ISO]

Similar to write(Stream,Term), but the names of atoms and functors are quoted where necessary to make the result acceptable as input to read/2, provided the same operator declarations are in effect. Same as write_term([Stream,] Term, [quoted(true),numbervars(true)]).

print(?Term) [Hookable]
print(+Stream,?Term) [Hookable]

Prints Term onto Stream. This predicate provides a handle for user defined pretty printing:

In particular, the debugging package prints the goals in the tracing messages, and the top-level prints the final values of variables. Thus you can vary the forms of these messages if you wish.

Note that on lists ([_|_]), print/2 will first give the whole list to user:portray/1, but if this fails it will only give each of the (top level) elements to user:portray/1. That is, user:portray/1 will not be called on all the tails of the list.

Same as write_term([Stream,] Term, [portrayed(true),numbervars(true)]).

portray(+Term) [Hook]
user:portray(+Term)

This should either print the Term and succeed, or do nothing and fail. In the latter case, the default printer (write/1) will print the Term.

portray_clause(?Clause)
portray_clause(+Stream,?Clause)

Writes the clause Clause onto Stream exactly as listing/[0,1] would have written it. Same as write_term([Stream,] Term, [quoted(true),numbervars(true),indented(true)]) followed by a period and a newline, removing redundant module prefixes and binding variables to terms of the form '$VAR'(N) yielding friendlier variable names.

write_term(+Term,+Options) [ISO]
write_term(+Stream,+Term,+Options) [ISO]

Same as write/[1,2] etc. with a list of options to provide extra control. This predicate in fact subsumes the above output predicates except portray_clause/[1,2] which additionally prints a period and a newline, and removes module prefixes that are redundant wrt. the current type-in module. Options is a list of zero or more of the following, where Boolean must be true or false (false is the default).

quoted(+Boolean)
If selected, functors are quoted where necessary to make the result acceptable as input to read/1. write_canonical/1, writeq/1, and portray_clause/1 select this.
ignore_ops(+Boolean)
If selected, Term is written in standard parenthesized notation instead of using operators. write_canonical/1 and display/1 select this.
portrayed(+Boolean)
If selected, user:portray/1 is called for each subterm. print/1 selects this.
numbervars(+Boolean)
If selected, occurrences of '$VAR'(N) where N is an integer >= 0 are treated specially (see numbervars/3). print/1, write/1, writeq/1, and portray_clause/1 select this.
cycles(+Boolean)
If selected, the potentially cyclic term is printed in finite @/2 notation, as discussed above.
indented(+Boolean)
If selected, the term is printed with the same indentation as is used by portray_clause/1 and listing/[0,1].
max_depth(N)
Depth limit on printing. N is an integer. 0 (the default) means no limit.

format(+Format,:Arguments)
format(+Stream,+Format,:Arguments)

Prints Arguments onto Stream according to format Format. Format is a list of formatting characters or character codes. If Format is an atom then is will be used to translate it into a list of character codes. Thus:

| ?- format("Hello world!", []).

has the same effect as

| ?- format('Hello world!', []).

no matter which value the double_quotes Prolog flag has.

format/2 and format/3 is a Prolog interface to the C stdio function printf(). It is modeled after and compatible with Quintus Prolog.

Arguments is a list of items to be printed. If there are no items then an empty list should be supplied.

The default action on a format character is to print it. The character ~ introduces a control sequence. To print a ~ repeat it:

| ?- format("Hello ~~world!", []).

will result in

Hello ~world!

The escape sequence (see Escape Sequences) \c (c for continue) is useful when formatting a string for readability. It causes all characters up to, but not including, the next non-layout character to be ignored.

| ?- format("Hello \c
             world!", []).

will result in

Hello world!

The general format of a control sequence is ~NC. The character C determines the type of the control sequence. N is an optional numeric argument. An alternative form of N is *. * implies that the next argument in Arguments should be used as a numeric argument in the control sequence. Example:

| ?- format("Hello~4cworld!", [0'x]).

and

| ?- format("Hello~*cworld!", [4,0'x]).

both produce

Helloxxxxworld!

The following control sequences are available.

~a
The argument is an atom. The atom is printed without quoting.
~Nc
(Print character.) The argument is a number that will be interpreted as a character code. N defaults to one and is interpreted as the number of times to print the character.
~Ne
~NE
~Nf
~Ng
~NG
(Print float). The argument is a float. The float and N will be passed to the C printf() function as
printf("%.Ne", Arg)
printf("%.NE", Arg)
printf("%.Nf", Arg)
printf("%.Ng", Arg)
printf("%.NG", Arg)

respectively.

If N is not supplied the action defaults to

printf("%e", Arg)
printf("%E", Arg)
printf("%f", Arg)
printf("%g", Arg)
printf("%G", Arg)

respectively.

~Nd
(Print decimal.) The argument is an integer. N is interpreted as the number of digits after the decimal point. If N is 0 or missing, no decimal point will be printed. Example:
| ?- format("Hello ~1d world!", [42]).
Hello 4.2 world!

| ?- format("Hello ~d world!", [42]).
Hello 42 world!

~ND
(Print decimal.) The argument is an integer. Identical to ~Nd except that , will separate groups of three digits to the left of the decimal point. Example:
| ?- format("Hello ~1D world!", [12345]).
Hello 1,234.5 world!

~Nr
(Print radix.) The argument is an integer. N is interpreted as a radix, 2 =< N =< 36. If N is missing the radix defaults to 8. The letters a-z will denote digits larger than 9. Example:
| ?- format("Hello ~2r world!", [15]).
Hello 1111 world!

| ?- format("Hello ~16r world!", [15]).
Hello f world!

~NR
(Print radix.) The argument is an integer. Identical to ~Nr except that the letters A-Z will denote digits larger than 9. Example:
| ?- format("Hello ~16R world!", [15]).
Hello F world!

~Ns
(Print string.) The argument is a list of character codes. Exactly N characters will be printed. N defaults to the length of the string. Example:
| ?- format("Hello ~4s ~4s!", ["new","world"]).
Hello new  worl!

| ?- format("Hello ~s world!", ["new"]).
Hello new world!

~i
(Ignore.) The argument, which may be of any type, is ignored. Example:
| ?- format("Hello ~i~s world!", ["old","new"]).
Hello new world!

~k
(Print canonical.) The argument may be of any type. The argument will be passed to write_canonical/1 (see Term I/O). Example:
| ?- format("Hello ~k world!", [[a,b,c]]).
Hello .(a,.(b,.(c,[]))) world!

~p
(Print.) The argument may be of any type. The argument will be passed to print/1 (see Term I/O). Example:
| ?- assert((portray([X|Y]) :- print(cons(X,Y)))).
| ?- format("Hello ~p world!", [[a,b,c]]).
Hello cons(a,cons(b,cons(c,[]))) world!

~q
(Print quoted.) The argument may be of any type. The argument will be passed to writeq/1 (see Term I/O). Example:
| ?- format("Hello ~q world!", [['A','B']]).
Hello ['A','B'] world!

~w
(Write.) The argument may be of any type. The argument will be passed to write/1 (see Term I/O). Example:
| ?- format("Hello ~w world!", [['A','B']]).
Hello [A,B] world!

~@
(Call.) The argument is a goal, which will be called and expected to print on the current output stream. If the goal performs other side-effects or does not succeed deterministically, the behavior is undefined. Example:
| ?- format("Hello ~@ world!", [write(new)]).
Hello new world!

~~
(Print tilde.) Takes no argument. Prints ~. Example:
| ?- format("Hello ~~ world!", []).
Hello ~ world!

~Nn
(Print newline.) Takes no argument. Prints N newlines. N defaults to 1. Example:
| ?- format("Hello ~n world!", []).
Hello
 world!

~N
(Print Newline.) Prints a newline if not at the beginning of a line.

The following control sequences set column boundaries and specify padding. A column is defined as the available space between two consecutive column boundaries on the same line. A boundary is initially assumed at line position 0. The specifications only apply to the line currently being written.

When a column boundary is set (~| or ~+) and there are fewer characters written in the column than its specified width, the remaining space is divided equally amongst the pad sequences (~t) in the column. If there are no pad sequences, the column is space padded at the end.

If ~| or ~+ specifies a position preceding the current position, the boundary is set at the current position.

~N|
Set a column boundary at line position N. N defaults to the current position.
~N+
Set a column boundary at N positions past the previous column boundary. N defaults to 8.
~Nt
Specify padding in a column. N is the fill character code. N may also be specified as `C where C is the fill character. The default fill character is <SPC>. Any (~t) after the last column boundary on a line is ignored.
Example:
| ?-
        format("~`*t NICE TABLE ~`*t~61|~n", []),
        format("*~t*~61|~n", []),
        format("*~t~a~20|~t~a~t~20+~a~t~20+~t*~61|~n",
               ['Right aligned','Centered','Left aligned']),
        format("*~t~d~20|~t~d~t~20+~d~t~20+~t*~61|~n",
               [123,45,678]),
        format("*~t~d~20|~t~d~t~20+~d~t~20+~t*~61|~n",
               [1,2345,6789]),
        format("~`*t~61|~n", []).

************************ NICE TABLE *************************
*                                                           *
*      Right aligned      Centered      Left aligned        *
*                123         45         678                 *
*                  1        2345        6789                *
*************************************************************


Node:Char I/O, Next:, Previous:Term I/O, Up:Input Output

Character Input/Output

Most of character I/O predicates have several variants:

bytes vs. characters
There are separate predicates for binary I/O, which work on bytes, and for text I/O, which work on characters. The former have the suffix _byte, e.g. put_byte.
character codes vs. one-char atoms
The text I/O predicates come in two variants, those which use character codes (suffix _code, e.g. put_code), and those using one-char atoms (suffix _char, e.g. put_char).
SICStus compatibility predicates
The SICStus compatibility predicates work on both binary and text streams and use character codes or bytes, depending on the stream type. They normally have no suffix (e.g. put), with the exception of peek_char.
explicit vs. implicit stream
Each of the above predicates comes in two variants: with an explicit first argument, which is the stream or alias to which the predicate applies (e.g. put_byte(Stream, Byte)), or without the stream argument, in which case the current input or output stream is used, depending on the context (e.g. put_byte(Byte)).
I/O on standard streams
These are variants of SICStus compatibility predicates which always work on the standard input or output. These predicates have the prefix tty, e.g. ttyput(Code).
nl [ISO]
nl(+Stream) [ISO]

A new line is started on the text stream Stream by printing an <LFD>. If Stream is connected to the terminal, its buffer is flushed.

get_code(?Code) [ISO]
get_code(+Stream,?Code) [ISO]

Code is the character code of the next character read from text stream Stream. If all characters of Stream have been read, Code is -1, and further calls to get_code/2 for the same stream will normally raise an exception, unless the stream is connected to the terminal (but see the eof_action option of open/4; see Stream Pred).

get_char(?Char) [ISO]
get_char(+Stream,?Char) [ISO]

Char is the one-char atom naming the next character read from text stream Stream. If all characters of Stream have been read, Char is end_of_file, and further calls to get_char/2 for the same stream will normally raise an exception, unless the stream is connected to the terminal (but see the eof_action option of open/4; see Stream Pred).

get_byte(?Byte) [ISO]
get_byte(+Stream,?Byte) [ISO]

Byte is the next byte read from the binary stream Stream. It has the same behavior at the end of stream as get_code.

get0(?Code) [Obsolescent]
get0(+Stream,?Code) [Obsolescent]

A combination of get_code and get_byte: Code is the next character code or byte read from the arbitrary stream Stream.

get(?N) [Obsolescent]
get(+Stream,?N) [Obsolescent]

Same as get0/2, except N is the character code of the next character that is not a layout-char (see Token String) read from Stream.

peek_code(?Code) [ISO]
peek_code(+Stream,?Code) [ISO]

Code is the character code of the next character from text stream Stream, or -1, if all characters of Stream have been read. The character is not actually read, it is only looked at and is still available for subsequent input.

peek_char(?Char) [ISO only]
peek_char(+Stream,?Char) [ISO only]

Char is the one-char atom naming the next character from text stream Stream, or end_of_file, if all characters of Stream have been read. The character is not actually read.

peek_char(?Code) [SICStus only]
peek_char(+Stream,?Code) [SICStus only]

Identical to peek_code.

peek_byte(?Byte) [ISO]
peek_byte(+Stream,?Byte) [ISO]

Byte is the next byte from binary stream Stream, or -1, if all bytes of Stream have been read. The byte is not actually read.

skip(+Code) [Obsolescent]
skip(+Stream,+Code) [Obsolescent]

Skips just past the next character code Code from Stream. Code may be an arithmetic expression.

skip_line [Obsolescent]
skip_line(+Stream) [Obsolescent]

Skips just past the next <LFD> from the text stream Stream.

put_code(+Code) [ISO]
put_code(+Stream,+Code) [ISO]

Character code Code is output onto text stream Stream. Code may be an arithmetic expression.

put_char(+Char) [ISO]
put_char(+Stream,+Char) [ISO]

The character named by the one-char atom Char is output onto text stream Stream.

put_byte(+Byte) [ISO]
put_byte(+Stream,+Byte) [ISO]

Byte Byte is output onto binary stream Stream. Byte may be an arithmetic expression.

put(+Code) [Obsolescent]
put(+Stream,+Code) [Obsolescent]

A combination of put_code and put_byte: Code is output onto (an arbitrary stream) Stream. Code may be an arithmetic expression.

tab(+N) [Obsolescent]
tab(+Stream,+N) [Obsolescent]

N spaces are output onto text stream Stream. N may be an arithmetic expression.

The above predicates are the ones which are the most commonly used, as they can refer to any streams. The predicates listed below always refer to the standard input and output streams. They are provided for compatibility with DEC-10 character I/O, and are actually redundant and easily recoded in terms of the above predicates.

ttynl [Obsolescent]

Same as nl(user_output).

ttyflush [Obsolescent]

Same as flush_output(user_output).

ttyget0(?N) [Obsolescent]

Same as get0(user_input, N).

ttyget(?N) [Obsolescent]

Same as get(user_input, N).

ttyput(+N) [Obsolescent]

Same as put(user_output, N).

ttyskip(+N) [Obsolescent]

Same as skip(user_input, N).

ttytab(+N) [Obsolescent]

Same as tab(user_output, N).


Node:Stream Pred, Next:, Previous:Char I/O, Up:Input Output

Stream I/O

The following predicates manipulate streams. Character, byte and line counts are maintained per stream. All streams connected to the terminal, however, share the same set of counts. For example, writing to user_output will advance the counts for user_input, if both are connected to the terminal. Bidirectional streams use the same counters for input and output.

Wherever a stream argument appears as input (+Stream), an alias can be used instead.

open(+FileName,+Mode,-Stream) [ISO]
open(+FileName,+Mode,-Stream,+Options) [ISO]

If FileName is a valid file name, the file is opened in mode Mode (invoking the UNIX function fopen) and the resulting stream is unified with Stream. Mode is one of:

read
Open the file for input.
write
Open the file for output. The file is created if it does not already exist, the file will otherwise be truncated.
append
Open the file for output. The file is created if it does not already exist, the file will otherwise be appended to.

If FileName is an integer, it is assumed to be a file descriptor passed to Prolog from C. The file descriptor is connected to a Prolog stream (invoking the POSIX function fdopen) which is unified with Stream.

Options is a list of zero or more of:

type(+T)
Specifies whether the stream is a text or binary stream. Default is text.
reposition(+Boolean)
Specifies whether repositioning is required for the stream (true), or not (false). The latter is the default.
alias(+A)
Specifies that the atom A is to be an alias for the stream.
eof_action(+Action)
Specifies what action is to be taken when the end of stream has already been reported (by returning -1 or end_of_file), and a further attempt to input is made. Action can have the following values:
error
An exception is raised. This is the default.
eof_code
An end of stream indicator (-1 or end_of_file) is returned again.
reset
The stream is considered not to be at end of stream and another attempt is made to input from it.

wcx(Wcx)
Specifies to pass the term Wcx to the wide character extension component; see Prolog Level WCX Features.

close(+X) [ISO]
close(+X, +Options) [ISO]

If X is a stream or alias, the stream is closed. If X is the name of a file opened by see/1 or tell/1, the corresponding stream is closed. Options is a list possibly containing the following element:

force(Boolean)
Specifies whether SICStus Prolog is to close the stream forcefully, even in the presence of errors (true), or not (false). The latter is the default. Currently this option has no effect.

absolute_file_name(+RelativeName,-AbsoluteName)

True if RelativeName can be expanded to an absolute file name (an atom) AbsoluteName, according to the filename syntax rules (see Input Output). This predicate will first search for a file with the suffix .pl added to the name given as an argument. If this fails, it will look for a file with no extra suffix added. If a file is found AbsoluteName is its absolute file name is returned. Otherwise, AbsoluteName is a valid expansion of RelativeName.

absolute_file_name/2 does not produce alternative expansions via backtracking.

If RelativeName is user, then AbsoluteName is also unified with user; this "filename" stands for the standard input or output stream, depending on context.

Variants of this predicate are used by all predicates that refer to filenames for resolving these. Predicates that load code require that the specified file exist, possibly with an extension.

file_search_path(+Alias,-Expansion) [Hook]
user:file_search_path(+Alias,-Expansion)

Specifies how to rewrite compound filenames to atomic ones, as described in Input Output. Alias should be an atom and Expansions a filename. The predicate may succeed non-deterministically in this search for an atomic filename.

The predicate exists as a dynamic, multifile predicate at startup with the following clause, defining an expansion for the library and system aliases. See State Info for more info on the Prolog flag host_type.

file_search_path(library, Path) :-
        library_directory(Path).
file_search_path(system, Platform) :-
        prolog_flag(host_type, Platform).

library_directory(-Directory) [Hook]
user:library_directory(-Directory)

Specifies a directory to be searched when a filename of the form library(Name) is used. The predicate exists as a dynamic, multifile predicate at startup with a single clause defining the location of the Prolog library. It may succeed non-deterministically in this search for a library directory.

current_input(?Stream) [ISO]

Stream is the current input stream. The current input stream is also accessed by the C variable SP_curin.

current_output(?Stream) [ISO]

Stream is the current output stream. The current output stream is also accessed by the C variable SP_curout.

current_stream(?FileName,?Mode,?Stream)

Stream is a stream which was opened in mode Mode and which is connected to the absolute file name Filename (an atom) or to the file descriptor Filename (an integer). This predicate can be used for enumerating all currently open streams through backtracking.

set_input(+Stream) [ISO]

Sets the current input stream to Stream.

set_output(+Stream) [ISO]

Sets the current output stream to Stream.

flush_output [ISO]
flush_output(+Stream) [ISO]

Flushes all internally buffered characters or bytes for Stream to the operating system.

open_null_stream(-Stream)

Opens a text output stream. Everything written to this stream will be thrown away.

character_count(+Stream,?N)

N is the number of characters read/written on text stream Stream.

byte_count(+Stream,?N)

N is the number of bytes read/written on stream Stream. Meaningful for both binary and text streams. In the latter case it will differ from the number returned by character_count/2 in the presence of wide characters.

line_count(+Stream,?N)

N is the number of lines read/written on text stream Stream.

line_position(+Stream,?N)

N is the number of characters read/written on the current line of text stream Stream.

stream_position(+Stream,?Position)

Position is a term representing the current position of Stream. The relative order of stream position terms can be tested with standard term comparison predicates such as compare/3, but you should not otherwise rely on their internal representation. This operation is available for any Prolog stream.

stream_property(?Stream, ?Property)) [ISO]

Stream Stream has property Property. Enumerates through backtracking all currently open streams, including the standard input/output/error streams, and all their properties.

Property can be one of the following:

file_name(?F)
F is the file name associated with the Stream.
mode(?M)
Stream has been opened in mode M.
input
Stream is an input stream.
output
Stream is an output stream.
alias(?A)
Stream has an alias A.
position(?P)
P is a term representing the current position of Stream. Same as stream_position(Stream, P).
end_of_stream(?E)
E describes the position of the input stream Stream, with respect to the end of stream. If not all characters have been read, then E is unified with not, otherwise (all characters read) but no end of stream indicator (-1 or end_of_file) was reported yet, then E is unified with at, otherwise E is unified with past.
eof_action(?A)
A is the end-of-file action applicable to Stream, cf. the eof_action option of open/4.
type(?T)
Stream is of type T.
wcx(?Wcx)
Wide character extension information Wcx was supplied at opening Stream; see Prolog Level WCX Features.

set_stream_position(+Stream,+Position) [ISO]

Position is a term representing a new position of Stream, which is then set to the new position. This operation is only available for Prolog streams connected to "seekable devices" (disk files, usually). If the option reposition(true) was supplied at the successful opening of the stream, then set_stream_position/2 is guaranteed to be successful.

seek(+Stream,+Offset,+Method,-NewLocation)

True if the stream Stream can be set to the byte offset Offset relative to Method, and NewLocation is the new byte offset from the beginning of the file after the operation. Method must be one of:

bof
Seek from the beginning of the file stream.
current
Seek from the current position of the file stream.
eof
Seek from the end of the file stream.

This operation is only available for Prolog streams connected to "seekable devices" (disk files, usually) and is an interface to the stdio functions fseek and ftell.

at_end_of_stream [ISO]
at_end_of_stream(+Stream) [ISO]

The end of stream has been reached for the input stream Stream. An input stream reaches end of stream when all characters (except EOF, i.e., -1) of the stream have been read. These predicates peek ahead for next input character if there is no character available on the buffer of Stream. Unless the stream is to be treated as connected to the terminal (see SP_force_interactive, Initializing the Prolog Engine), a stream remains at end of stream after EOF has been read, and any further attempt to read from the stream will raise an existence error (see Exception).

at_end_of_line
at_end_of_line(+Stream)

The end of stream or end of line has been reached for the input stream Stream. An input stream reaches end of line when all the characters except <LFD> of the current line have been read. These predicates peek ahead for next input character if there is no character available on the buffer of Stream.

fileerrors

Undoes the effect of nofileerrors/0.

nofileerrors

After a call to this predicate, failure to locate or open a file will cause the operation to fail instead of the default action, which is to raise an exception with an error message.

stream_select(+Streams,+TimeOut,-ReadStreams)

The list of streams in Streams is checked for readable characters. A stream can be any stream associated with an I/O descriptor. The list ReadStreams returns the streams with readable data. If TimeOut is instantiated to off, the predicate waits until something is available. If TimeOut is S:U the predicate waits at most S seconds and U microseconds. Both S and U must be integers >=0. If there is a timeout, ReadStreams is [].

Not available in operating systems that do not support the system() system call.

stream_interrupt(+Stream,?OldHandler,?NewHandler)

Installs NewHandler as an interrupt-handler which is invoked when something is readable on Stream. OldHandler is the current interrupt handler Stream must be associated with an I/O descriptor. Interrupt handlers are specified as atoms. The atom off indicates that the interrupt mechanism is turned off for Stream. Any other atom is the name of a predicate invoked when something is readable on Stream. The handler predicate has one argument, the stream that is readable. For example,

stream_interrupt(Stream, _, int_handler).
will enable the interrupt mechanism. Given the predicate
int_handler(Stream) :-
        read(Stream, Data),
        write(Data), nl.

the term read from Stream will be written to the current output. NOTE: there is no guarantee that a complete Prolog term is available yet. If not, read/2 will suspend as usual.

Not available in operating systems that do not provide the ability to generate signals when new data becomes available on a file descriptor.


Node:File Pred, Next:, Previous:Stream Pred, Up:Input Output

DEC-10 Prolog File I/O

The following predicates manipulate files.

see(+File)

The file File becomes the current input stream. File may be a stream previously opened by see/1 or a filename. If it is a filename, the following action is taken: If there is a stream opened by see/1 associated with the same file already, then it becomes the current input stream. Otherwise, the file File is opened for input and made the current input stream.

seeing(?FileName)

FileName is unified with the name of the current input file, if it was opened by see/1, with the current input stream, if it is not user_input, otherwise with user.

seen

Closes the current input stream, and resets it to user_input.

tell(+File)

The file File becomes the current output stream. File may be a stream previously opened by tell/1 or a filename. If it is a filename, the following action is taken: If there is a stream opened by tell/1 associated with the same file already, then it becomes the current output stream. Otherwise, the file File is opened for output and made the current output stream.

telling(?FileName)

FileName is unified with the name of the current output file, if it was opened by tell/1, with the current output stream, if it is not user_output, otherwise with user.

told

Closes the current output stream, and resets it to user_output.


Node:I/O Example, Previous:File Pred, Up:Input Output

An Example

Here is an example of a common form of file processing:

process_file(F) :-
        seeing(OldInput),
        see(F),                 % Open file F
        repeat,
          read(T),              % Read a term
          process_term(T),      % Process it
          T == end_of_file,     % Loop back if not at end of file
        !,
        seen,                   % Close the file
        see(OldInput).

The above is an example of a repeat loop. Nearly all sensible uses of repeat/0 follow the above pattern. Note the use of a cut to terminate the loop.


Node:Arithmetic, Next:, Previous:Input Output, Up:Built Intro

Arithmetic

Arithmetic is performed by built-in predicates which take as arguments arithmetic expressions and evaluate them. An arithmetic expression is a term built from numbers, variables, and functors that represent arithmetic functions. At the time of evaluation, each variable in an arithmetic expression must be bound to a non-variable expression. An expression evaluates to a number, which may be an integer or a float.

The range of integers is [-2^2147483616, 2^2147483616). Thus for all practical purposes, the range of integers can be considered infinite.

The range of floats is the one provided by the C double type, typically [4.9e-324, 1.8e+308] (plus or minus). In case of overflow or division by zero, iso execution mode will raise an evaluation error exception. In sicstus execution mode no exceptions will be raised, instead appropriate infinity values, as defined by the IEEE standard, will be used.

Only certain functors are permitted in an arithmetic expression. These are listed below, together with an indication of the functions they represent. X and Y are assumed to be arithmetic expressions. Unless stated otherwise, the arguments of an expression may be any numbers and its value is a float if any of its arguments is a float, otherwise the value is an integer. Any implicit coercions are performed with the integer/1 and float/1 functions.

The arithmetic functors are annotated with [ISO], [ISO only], or [SICStus only], with the same meaning as for the built-in predicates; see ISO Compliance.

+(X)
The value is X.
-X [ISO]
The value is the negative of X.
X+Y [ISO]
The value is the sum of X and Y.
X-Y [ISO]
The value is the difference of X and Y.
X*Y [ISO]
The value is the product of X and Y.
X/Y [ISO]
The value is the float quotient of X and Y.
X//Y [ISO]
The value is the integer quotient of X and Y. The result is always truncated towards zero. In iso execution mode X and Y have to be integers.
X rem Y [ISO]
The value is the integer remainder after dividing X by Y, i.e. integer(X)-integer(Y)*(X//Y). The sign of a nonzero remainder will thus be the same as that of the dividend. In iso execution mode X and Y have to be integers.
X mod Y [ISO only]
The value is X modulo Y, i.e. integer(X)-integer(Y)*floor(X/Y). The sign of a nonzero remainder will thus be the same as that of the divisor. X and Y have to be integers.
X mod Y [SICStus only]
The value is the same as that of X rem Y.
integer(X)
The value is the closest integer between X and 0, if X is a float, otherwise to X itself.
float_integer_part(X) [ISO]
The same as integer(X). In iso execution mode X has to be a float.
float_fractional_part(X) [ISO]
The value is the fractional part of X, i.e. X - float_integer_part(X). In iso execution mode X has to be a float.
float(X) [ISO]
The value is the float equivalent of X, if X is an integer, otherwise to X itself.
X/\Y [ISO]
The value is the bitwise conjunction of the integers X and Y. In iso execution mode X and Y have to be integers.
X\/Y [ISO]
The value is the bitwise disjunction of the integers X and Y. In iso execution mode X and Y have to be integers.
X#Y
The value is the bitwise exclusive or of the integers X and Y.
\(X) [ISO]
The value is the bitwise negation of the integer X. In iso execution mode X has to be an integer.
X<<Y [ISO]
The value is the integer X shifted left by Y places. In iso execution mode X and Y have to be integers.
X>>Y [ISO]
The value is the integer X shifted right by Y places. In iso execution mode X and Y have to be integers.
[X]
A list of just one number X evaluates to X. Since a quoted string is just a list of integers, this allows a quoted character to be used in place of its character code; e.g. "A" behaves within arithmetic expressions as the integer 65.

SICStus Prolog also includes an extra set of functions listed below. These may not be supported by other Prologs. All trigonometric and transcendental functions take float arguments and deliver float values. The trigonometric functions take arguments or deliver values in radians.


abs(X) [ISO]
The value is the absolute value of X.
sign(X) [ISO]
The value is the sign of X, i.e. -1, if X is negative, 0, if X is zero, and 1, if X is positive, coerced into the same type as X (i.e. the result is an integer, iff X is an integer).
gcd(X,Y)
The value is the greatest common divisor of the two integers X and Y. In iso execution mode X and Y have to be integers.
min(X,Y)
The value is the lesser value of X and Y.
max(X,Y)
The value is the greater value of X and Y.
msb(X)
The value is the most significant bit position of the integer X. It is equivalent to, but more efficient than, integer(log(2,X)). In iso execution mode X has to be an integer.
round(X) [ISO only]
The value is the closest integer to X. X has to be a float. If X is exactly half-way between two integers, it is rounded up (i.e. the value is the least integer greater than X).
round(X) [SICStus only]
The value is the float that is the closest integral value to X. If X is exactly half-way between two integers, it is rounded to the closest even integral value.
truncate(X) [ISO only]
The value is the closest integer between X and 0. X has to be a float.
truncate(X) [SICStus only]
The value is the float that is the closest integer between X and 0.
floor(X) [ISO only]
The value is the greatest integer less or equal to X. X has to be a float.
floor(X) [SICStus only]
The value is the float that is the greatest integral value less or equal to X.
ceiling(X) [ISO only]
The value is the least integer greater or equal to X. X has to be a float.
ceiling(X) [SICStus only]
The value is the float that is the least integral value greater or equal to X.
sin(X) [ISO]
The value is the sine of X.
cos(X) [ISO]
The value is the cosine of X.
tan(X)
The value is the tangent of X.
cot(X)
The value is the cotangent of X.
sinh(X)
The value is the hyperbolic sine of X.
cosh(X)
The value is the hyperbolic cosine of X.
tanh(X)
The value is the hyperbolic tangent of X.
coth(X)
The value is the hyperbolic cotangent of X.
asin(X)
The value is the arc sine of X.
acos(X)
The value is the arc cosine of X.
atan(X) [ISO]
The value is the arc tangent of X.
atan2(X,Y)
The value is the four-quadrant arc tangent of X and Y.
acot(X)
The value is the arc cotangent of X.
acot2(X,Y)
The value is the four-quadrant arc cotangent of X and Y.
asinh(X)
The value is the hyperbolic arc sine of X.
acosh(X)
The value is the hyperbolic arc cosine of X.
atanh(X)
The value is the hyperbolic arc tangent of X.
acoth(X)
The value is the hyperbolic arc cotangent of X.
sqrt(X) [ISO]
The value is the square root of X.
log(X) [ISO]
The value is the natural logarithm of X.
log(Base,X)
The value is the logarithm of X in the base Base.
exp(X) [ISO]
The value is the natural exponent of X.
X ** Y [ISO]
exp(X,Y)
The value is X raised to the power of Y.
inf [SICStus only]
The value is infinity as defined in the IEEE standard.
nan [SICStus only]
The value is not-a-number as defined in the IEEE standard.

Variables in an arithmetic expression which is to be evaluated may be bound to other arithmetic expressions rather than just numbers, e.g.

evaluate(Expression, Answer) :- Answer is Expression.

| ?- evaluate(24*9, Ans).
Ans = 216 ?

yes

Arithmetic expressions, as described above, are just data structures. If you want one evaluated you must pass it as an argument to one of the built-in predicates listed below. Note that is/2 only evaluates one of its arguments, whereas all the comparison predicates evaluate both of theirs. In the following, X and Y stand for arithmetic expressions, and Z for some term.

Z is X [ISO]

X, which must be an arithmetic expression, is evaluated and the result is unified with Z.

X =:= Y [ISO]

The numeric values of X and Y are equal.

X =\= Y [ISO]

The numeric values of X and Y are not equal.

X < Y [ISO]

The numeric value of X is less than the numeric value of Y.

X > Y [ISO]

The numeric value of X is greater than the numeric value of Y.

X =< Y [ISO]

The numeric value of X is less than or equal to the numeric value of Y.

X >= Y [ISO]

The numeric value of X is greater than or equal to the numeric value of Y.


Node:Term Compare, Next:, Previous:Arithmetic, Up:Built Intro

Comparison of Terms

These built-in predicates are meta-logical. They treat uninstantiated variables as objects with values which may be compared, and they never instantiate those variables. They should not be used when what you really want is arithmetic comparison (see Arithmetic) or unification.

The predicates make reference to a standard total ordering of terms, which is as follows:

For example, here is a list of terms in standard order:

[ X, -1.0, -9, 1, fie, foe, X = Y, foe(0,2), fie(1,1,1) ]

NOTE: the standard order is only well-defined for finite (acyclic) terms. There are infinite (cyclic) terms for which no order relation holds. Furthermore, blocking goals (see Procedural) on variables or modifying their attributes (see Attributes) does not preserve their order.

These are the basic predicates for comparison of arbitrary terms:

Term1 == Term2 [ISO]

The terms currently instantiating Term1 and Term2 are literally identical (in particular, variables in equivalent positions in the two terms must be identical). For example, the query

| ?- X == Y.

fails (answers no) because X and Y are distinct uninstantiated variables. However, the query

| ?- X = Y, X == Y.

succeeds because the first goal unifies the two variables (see Misc Pred).

Term1 \== Term2 [ISO]

The terms currently instantiating Term1 and Term2 are not literally identical.

Term1 @< Term2 [ISO]

The term Term1 is before the term Term2 in the standard order.

Term1 @> Term2 [ISO]

The term Term1 is after the term Term2 in the standard order.

Term1 @=< Term2 [ISO]

The term Term1 is not after the term Term2 in the standard order.

Term1 @>= Term2 [ISO]

The term Term1 is not before the term Term2 in the standard order.

Some further predicates involving comparison of terms are:

?=(?X,?Y)

X and Y are either syntactically identical or syntactically non-unifiable.

compare(?Op,?Term1,?Term2)

The result of comparing terms Term1 and Term2 is Op, where the possible values for Op are:

=
if Term1 is identical to Term2,
<
if Term1 is before Term2 in the standard order,
>
if Term1 is after Term2 in the standard order.

Thus compare(=,Term1,Term2) is equivalent to Term1 == Term2.

sort(+List1,?List2)

The elements of the list List1 are sorted into the standard order (see Term Compare) and any identical elements are merged, yielding the list List2. (The time and space complexity of this operation is at worst O(N lg N) where N is the length of List1.)

keysort(+List1,?List2)

The list List1 must consist of pairs of the form Key-Value. These items are sorted into order according to the value of Key, yielding the list List2. No merging takes place. This predicate is stable, i.e. if K-A occurs before K-B in the input, then K-A will occur before K-B in the output. (The time and space complexity of this operation is at worst O(N lg N) where N is the length of List1.)


Node:Control, Next:, Previous:Term Compare, Up:Built Intro

Control

+P , +Q [ISO]

P and Q.

+P ; +Q [ISO]

P or Q.

! [ISO]

See Cut.

\+ +P [ISO]

Fails if the goal P has a solution, and succeeds otherwise. This is not real negation ("P is false"), but a kind of pseudo-negation meaning "P is not provable". It is defined as if by

\+(P) :- P, !, fail.
\+(_).

In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

Remember that with prefix operators such as this one it is necessary to be careful about spaces if the argument starts with a (. For example:

| ?- \+ (P,Q).

is this operator applied to the conjunction of P and Q, but

| ?- \+(P,Q).

would require a predicate \+ /2 for its solution. The prefix operator can however be written as a functor of one argument; thus

| ?- \+((P,Q)).

is also correct.

+P -> +Q ; +R [ISO]

Analogous to

if P then Q else R

and defined as if by

(P -> Q; R) :- P, !, Q.
(P -> Q; R) :- R.

except the scope of any cut in Q or R extends beyond the if-then-else construct. In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

Note that this form of if-then-else only explores the first solution to the goal P.

Note also that the ; is not read as a disjunction operator in this case; instead, it is part of the if-then-else construction.

The precedence of -> is less than that of ; (see Operators), so the expression is read as

;(->(P,Q),R)

+P -> +Q [ISO]

When occurring as a goal, this construction is read as equivalent to

(P -> Q; fail)

if(+P,+Q,+R)

Analogous to

if P then Q else R

but differs from P -> Q ; R in that if(P, Q, R) explores all solutions to the goal P. There is a small time penalty for this--if P is known to have only one solution of interest, the form P -> Q ; R should be preferred.

In sicstus execution mode no cuts are allowed in P. In iso execution mode cuts are allowed in P and their scope is the goal P.

once(+P) [ISO]

Finds the first solution, if any, of goal P. Fails if no solutions are found. Will not explore further solutions on backtracking. Equivalent to

(P -> true; fail)

otherwise
true [ISO]

These always succeed. Use of otherwise/0 is discouraged, because it is not as portable as true/0, and because the former may suggest a completely different semantics than the latter.

false
fail [ISO]

These always fail. Use of false/0 is discouraged, because it is not as portable as fail/0, and because the latter has a more procedural flavor to it.

repeat [ISO]

Generates an infinite sequence of backtracking choices. In sensible code, repeat/0 is hardly ever used except in repeat loops. A repeat loop has the structure

Head :-
        ...
        save(OldState),
        repeat,
          generate(Datum),
          action(Datum),
          test(Datum),
        !,
        restore(OldState),
        ...

The purpose is to repeatedly perform some action on elements which are somehow generated, e.g. by reading them from a stream, until some test becomes true. Usually, generate, action, and test are all determinate. Repeat loops cannot contribute to the logic of the program. They are only meaningful if the action involves side-effects.

The only reason for using repeat loops instead of a more natural tail-recursive formulation is efficiency: when the test fails back, the Prolog engine immediately reclaims any working storage consumed since the call to repeat/0.

call(:Term) [ISO]
incore(:Term) [Obsolescent]
:Term

If Term is instantiated to a term which would be acceptable as the body of a clause, then the goal call(Term) is executed exactly as if that term appeared textually in its place, except that any cut (!) occurring in Term only cuts alternatives in the execution of Term. Use of incore/1 is not recommended.

If Term is not instantiated as described above, an error message is printed and the call fails.

call_cleanup(:Goal,:Cleanup)

This construction can be used to ensure that Cleanup is executed as soon as Goal has completed execution, no matter how it finishes. In more detail:

When call_cleanup/2 with a continuation C is called or backtracked into, first Goal is called or backtracked into. Then there are four possibilities:

  1. Goal succeeds deterministically, possibly leaving some blocked subgoals. Cleanup is executed with continuation C.
  2. Goal succeeds with some alternatives outstanding. Execution proceeds to C. If a cut that removes the outstanding alternatives is encountered, Cleanup is executed with continuation to proceed after the cut. Also, if an exception E that will be caught by an ancestor of the call_cleanup/2 Goal is raised, Cleanup is executed with continuation raise_exception(E).
  3. Goal fails. Cleanup is executed with continuation fail.
  4. Goal raises an exception E. Cleanup is executed with continuation raise_exception(E).

In a typical use of call_cleanup/2, Cleanup succeeds deterministically after performing some side-effect; otherwise, unexpected behavior may result.

Note that the Prolog top level operates as a read-execute-fail loop, which backtracks into or cuts the query when the user types ; or <RET> respectively. Also, the predicates halt/0, abort/0, and reinitialise/0 are implemented in terms of exceptions. All of these circumstances can trigger the execution of Cleanup.


Node:Exception, Next:, Previous:Control, Up:Built Intro

Error and Exception Handling

The built-in predicates described in this section are used to alter the control flow to meet exception and error conditions. The equivalent of a raise_exception/1 is also executed by the built-in predicates when errors occur.

catch(:ProtectedGoal,?Pattern,:Handler) [ISO]
on_exception(?Pattern,:ProtectedGoal,:Handler)
throw(+Exception) [ISO]
raise_exception(+Exception)

catch/3 is the same as on_exception/3 (but note different argument order), and throw/1 is the same as raise_exception/1. on_exception/3 calls ProtectedGoal. If this succeeds or fails, so does the call to on_exception/3. If however, during the execution of ProtectedGoal, there is a call to raise_exception(Exception), then Exception is copied and the stack is unwound back to the call to on_exception/3, whereupon the copy of Exception is unified with Pattern. If this unification succeeds, then on_exception/3 calls the goal Handler in order to determine the success or failure of on_exception/3. Otherwise, the stack keeps unwinding, looking for an earlier invocation of on_exception/3. Exception may be any term.

In a development system, any previously uncaught exception is caught and an appropriate error message is printed before returning to the top level. In recursive calls to Prolog from C, uncaught exceptions are returned back to C instead. The printing of these and other messages in a development system is handled by the predicate print_message/2. The behavior of this predicate can be overridden by defining user:portray_message/2, so as to suppress or alter the format of certain messages. These predicates work as follows:

print_message(+Severity, +Message) [Hookable]

Most messages from the system are printed by calling this predicate. Before anything is printed, however, print_message/2 calls user:portray_message/2 with the same arguments, so as to give the user a means of intercepting the message before it is actually printed. If user:portray_message/2 succeeds, nothing is printed, otherwise Message is formatted and printed using the default method. In runtime systems, the message is printed unformatted.

Message is a term that encodes the message to be printed. The format of message terms is subject to change, but can be inspected in the file Bips/msgs.pl of the SICStus Prolog distribution. Severity is a term denoting the severity of the message, and is one of:

force(Severity)
Message should be printed without calling the user:portray_message/2 hook. This is useful if user:portray_message/2 has intercepted the message, and now wants to print a reformatted version of it using print_message/2.
error
Message is an uncaught exception. The execution will normally be aborted and return to the top level. Syntax errors and exceptions that occur while loading files do not necessarily abort the execution, however.
warning
Message is a warning (e.g. singleton variables).
informational
Message provides information e.g. about files being loaded. Such messages are suppressed in runtime systems, but can be intercepted by user:portray_message/2.
help
Message is normally a response to a query.

portray_message(+Severity, +Message) [Hook]
user:portray_message(+Severity, +Message)

Called by print_message/2 before printing the message. If this succeeds, the default message for printing Message is overridden, and nothing more is printed.

The format of the exception raised by the built-in predicates depends on the execution mode. In iso execution mode the format is

        error(ISO_Error, SICStus_Error)

where ISO_Error is the error term prescribed by the ISO Prolog standard, while SICStus_Error is the part defined by the standard to be implementation dependent. In case of SICStus Prolog this is the SICStus error term, which normally contains additional information, such as the goal and the argument number causing the error.

In sicstus execution mode, the SICStus error term is used when raising an exception in a built-in predicate.

The list below itemizes the error terms, showing the ISO_Error and SICStus_Error form of each one, in that order. Note that the SICStus and ISO error terms do not always belong to the same error class, and that the context and consistency error classes are extensions to the ISO Prolog standard.

The goal part of the error term may optionally have the form $@(Callable,PC) where PC is an internal encoding of the line of code containing the culprit goal or one of its ancestors.

instantiation_error
instantiation_error(Goal,ArgNo)
Goal was called with insufficiently instantiated variables.
type_error(TypeName,Culprit)
type_error(Goal,ArgNo,TypeName,Culprit)
Goal was called with the wrong type of argument(s). TypeName is the expected type and Culprit what was actually found.
domain_error(Domain,Culprit)
domain_error(Goal,ArgNo,Domain,Culprit)
Goal was called with argument(s) of the right type but with illegal value(s). Domain is the expected domain and Culprit what was actually found.
existence_error(ObjectType,Culprit)
existence_error(Goal,ArgNo,ObjectType,Culprit,Reserved)
Something does not exist as indicated by the arguments. If the unknown-flag (see prolog_flag/3) is set to error, this error is raised with ArgNo set to 0 when an undefined predicate is called.
permission_error(Operation,ObjectType,Culprit)
permission_error(Goal,Operation,ObjectType,Culprit,Reserved)
The Operation is not permitted on Culprit of the ObjectType.
context_error(ContextType,CommandType)
context_error(Goal,ContextType,CommandType)
The CommandType is not permitted in ContextType.
syntax_error(Message)
syntax_error(Goal,Position,Message,Tokens,AfterError)
A syntax error was found when reading a term with read/[1,2] or assembling a number from its characters with number_chars/2. In the former case this error is raised only if the syntax_errors flag (see prolog_flag/3) is set to error.
evaluation_error(ErrorType,Culprit)
evaluation_error(Goal,ArgNo,ErrorType,Culprit)
An incorrect arithmetic expression was evaluated. Only occurs in iso execution mode.
representation_error(ErrorType)
representation_error(Goal,ArgNo,ErrorType)
A representation error occurs when the program tries to compute some well-defined value which cannot be represented, such as a compound term with arity > 255.
consistency_error(Culprit1,Culprit2,Message)
consistency_error(Goal,Culprit1,Culprit2,Message)
A consistency error occurs when two otherwise valid values or operations have been specified which are inconsistent with each other.
resource_error(ResourceType)
resource_error(Goal,ResourceType)
A resource error occurs when SICStus Prolog has insufficient resources to complete execution. Currently no such error is raised.
system_error
system_error(Message)
An error occurred while dealing with the operating system.

It is possible to handle a particular kind of existence errors locally: calls to undefined predicates. This can be done by defining clauses for:

unknown_predicate_handler(+Goal,+Module,-NewGoal) [Hook]
user:unknown_predicate_handler(+Goal,+Module,-NewGoal)

Called as a result of a call to an undefined predicate. Goal is bound to the goal of the undefined predicate and Module to the module where the call was made. If this predicate succeeds, Module:NewGoal is called; otherwise, the action taken is governed by the unknown Prolog flag.

The following example shows an auto-loader for library packages:

user:unknown_predicate_handler(Goal, Module, Goal) :-
        functor(Goal, Name, Arity),
        require(Module:(Name/Arity)).


Node:State Info, Next:, Previous:Exception, Up:Built Intro

Information about the State of the Program

listing

Lists onto the current output stream all the clauses in the current interpreted program (in the type-in module; see Module Spec). Clauses listed onto a file can be consulted back.

listing(:Spec)

Lists all interpreted predicates covered by the generalized predicate spec Spec. For example:

| ?- listing([concatenate/3, reverse, m:go/[2-3], bar:_]).

current_atom(?Atom)

Atom is an atom known to SICStus Prolog. Can be used to enumerate (through backtracking) all currently known atoms, and return each one as Atom.

current_predicate(?Name,:Head)
current_predicate(?Name,-Head)

Name is the name of a user defined or library predicate, and Head is the most general goal for that predicate, possibly prefixed by a module name. This predicate can be used to enumerate all user defined or library predicates through backtracking.

current_predicate(?Name/?Arity) [ISO]

Name is the name of a user defined or library predicate, possibly prefixed by a module name and Arity is its arity. This predicate can be used to enumerate all user defined or library predicates through backtracking.

predicate_property(:Head,?Property)
predicate_property(-Head,?Property)

Head is the most general goal for an existing predicate, possibly prefixed by a module name, and Property is a property of that predicate, where the possible properties are

This predicate can be used to enumerate all existing predicates and their properties through backtracking.

current_module(?Module)

Module is a module in the system. It can be used to backtrack through all modules present in the system.

current_module(?Module, ?File)

Module is the module defined in File.

module(+Module)

The type-in module is set to Module.

set_prolog_flag(+FlagName,+NewValue) [ISO]
prolog_flag(+FlagName,?OldValue,?NewValue)

OldValue is the value of the Prolog flag FlagName, and the new value of FlagName is set to NewValue. The possible Prolog flag names and values are:

agc_margin
An integer Margin. The atoms will be garbage collected when Margin new atoms have been created since the last atom garbage collection. Initially 10000.
argv
A read-only flag. The value is a list of atoms of the program arguments supplied when the current SICStus Prolog process was started. For example, if SICStus Prolog were invoked with:
% sicstus -a hello world 2001

then the value will be [hello,world,'2001'].

bounded [ISO]
A read-only flag, one of the flags defining the integer type. For SICStus, its value is false, indicating that the domain of integers is practically unbounded.
char_conversion [ISO]
If this flag is on, unquoted characters in terms and programs read in will be converted, as specified by previous invocations of char_conversion/2. If the flag is off no conversion will take place. The default value is on.
compiling
Governs the mode in which compile/1 and fcompile/1 operate (see Load Intro).
compactcode
Compilation produces byte-coded abstract instructions (the default).
fastcode
Compilation produces native machine instructions. Currently only available for Sparc platforms.
profiledcode
Compilation produces byte-coded abstract instructions instrumented to produce execution profiling data.
debugcode
Compiling is replaced by consulting.

debugging
Corresponds to the predicates debug/0, nodebug/0, trace/0, notrace/0, zip/0, nozip/0 (see Debug Pred). The flag describes the mode the debugger is in, or is required to be switched to:
trace
Trace mode (the debugger is creeping).
debug
Debug mode (the debugger is leaping).
zip
Zip mode (the debugger is zipping).
off
The debugger is switched off (the default).

debug [ISO]
The flag debug, prescribed by the ISO Prolog standard, is a simplified form of the debugging flag:
off
The debugger is switched off (the default).
on
The debugger is switched on (to trace mode, if previously switched off).

(The flags debugging and debug are not available in runtime systems.)

double_quotes [ISO]
Governs the interpretation of double quoted strings (see Compound Terms):
codes
List of character codes comprising the string.
chars
List of one-char atoms comprising the string.
atom
The atom composed of the same characters as the string.

character_escapes
on or off. If this flag is on, a backslash occurring inside integers in 0' notation or inside quoted atoms or strings has special meaning, and indicates the start of an escape sequence (see Escape Sequences). This flag is relevant when reading as well as when writing terms, and is initially on.
debugger_print_options
The value is a list of options for write_term/3 (see Term I/O), to be used in the debugger's messages. Not available in runtime systems. The initial value is [quoted(true),numbervars(true),portrayed(true),max_depth(10)].
discontiguous_warnings
on or off. Enable or disable warning messages when clauses are not together in source files. Initially on. (This warning is always disabled in runtime systems.)
fileerrors
on or off. Enables or disables raising of file error exceptions. Equivalent to fileerrors/0 and nofileerrors/0, respectively (see Stream Pred). Initially on (enabled).
gc
on or off. Enables or disables garbage collection of the global stack. Initially on (enabled).
gc_margin
Margin: At least Margin kilobytes of free global stack space are guaranteed to exist after a garbage collection. Also, no garbage collection is attempted unless the global stack is at least Margin kilobytes. Initially 1000.
gc_trace
Governs global stack garbage collection trace messages.
verbose
Turn on verbose tracing of garbage collection.
terse
Turn on terse tracing of garbage collection.
off
Turn off tracing of garbage collection (the default).

host_type
A read-only flag. The value is an atom identifying the platform on which SICStus was compiled, such as 'x86-linux-glibc2.1' or 'sparc-solaris-5.6'.
integer_rounding_function [ISO]
A read-only flag, one of the flags defining the integer type. In SICStus Prolog its value is toward_zero, indicating that the integer division ((//)/2) and integer remainder (rem/2) arithmetic functions use rounding toward zero; see Arithmetic.
language
iso or sicstus. Selects the execution mode specified.
max_arity [ISO]
A read-only flag, specifying the maximum arity allowed for a compound term. In SICStus Prolog this is 255.
max_integer [ISO]
A read-only flag, specifying the largest possible integer value. As in SICStus Prolog the range of integers in not bounded, prolog_flag/3 and current_prolog_flag/2 will fail, when accessing this flag.
min_integer [ISO]
A read-only flag, specifying the smallest possible integer value. As in SICStus Prolog the range of integers in not bounded, prolog_flag/3 and current_prolog_flag/2 will fail, when accessing this flag.
redefine_warnings
on or off. Enable or disable warning messages when :
  • a module or predicate is being redefined from a different file than its previous definition. Such warnings are currently not issued when a .po file is being loaded.
  • a predicate is being imported while it was locally defined already.
  • a predicate is being redefined locally while it was imported already.
  • a predicate is being imported while it was imported from another module already.

Initially on. (This warning is always disabled in runtime systems.)

single_var_warnings
on or off. Enable or disable warning messages when a clause containing variables not beginning with _ occurring once only is compiled or consulted. Initially on.
source_info
emacs or on or off. If not off while source code is being loaded, information about line numbers and filenames are stored with the loaded code. If the value is on while debugging, this information is used to print the source code location while prompting for a debugger command. If the value is on while printing an uncaught error exception message, the information is used to print the source code location of the culprit goal or one of its ancestors, as far as it can be determined. If the value is emacs in any of these cases, the appropriate line of code is instead highlighted, and no extra text is printed. The value is off initially, and that is its only available value in runtime systems.
syntax_errors
Controls what action is taken upon syntax errors in read/[1,2].
dec10
The syntax error is reported and the read is repeated.
error
An exception is raised. See Exception. (the default).
fail
The syntax error is reported and the read fails.
quiet
The read quietly fails.

system_type
A read-only flag. The value is development in development systems and runtime in runtime systems.
toplevel_print_options
The value is a list of options for write_term/3 (see Term I/O), to be used when the top level displays variable bindings, answer constraints, and uncaught exceptions. Not available in runtime systems. The initial value is [quoted(true),numbervars(true),portrayed(true),max_depth(10)].
typein_module
Permitted values are atoms. Controls the current type-in module (see Module Spec). Corresponds to the predicate module/1.
unknown [ISO]
Corresponds to the predicate unknown/2 (see Debug Pred).
trace
Causes calls to undefined predicates to be reported and the debugger to be entered at the earliest opportunity. (This setting is not possible in runtime systems.)
fail
Causes calls to such predicates to fail.
warning
Causes calls to such predicates to display a warning message and then fail.
error
Causes calls to such predicates to raise an exception (the default). See Exception.

user_input
Permitted values are any stream opened for reading. Controls which stream is referenced by user_input and SP_stdin. It is initially set to a stream connected to UNIX stdin.
user_output
Permitted values are any stream opened for writing. Controls which stream is referenced by user_output and SP_stdout. It is initially set to a stream connected to UNIX stdout.
user_error
Permitted values are any stream opened for writing. Controls which stream is referenced by user_error and SP_stderr. It is initially set to a stream connected to UNIX stderr.
version
A read-only flag. The value is an atom containing the banner text displayed on startup and reinitialization, such as 'SICStus 3 #0: Wed Mar 15 12:29:29 MET 1995'.
wcx
The value of the flag is the default term to be passed to the wide character extension component; see Prolog Level WCX Features.

prolog_flag(?FlagName,?Value)
current_prolog_flag(?FlagName,?Value) [ISO]

Value is the current value of the Prolog flag FlagName. Can be used to enumerate all Prolog flags and their values by backtracking.

prolog_load_context(?Key,?Value)

This predicate gives access to context variables during compilation and loading of Prolog files. It unifies Value with the value of the variable identified by Key. Possible keys are:

source
The absolute path name of the file being compiled. During loading of a .po or .ql file, the corresponding source file name is returned.
file
Outside included files (see Include Declarations) this is the same as the source key. In included files this is the absolute path name of the file being included.
directory
The absolute path name of the directory of the file being compiled/loaded. In included files this is the directory of the file being included.
module
The source module (see Meta Exp). This is useful for example if you are defining clauses for user:term_expansion/[2,4] and need to access the source module at compile time.
stream
The stream being compiled or loaded from.
term_position
A term representing the position of the last clause read (see Stream Pred).

statistics

Displays on the standard error stream statistics relating to memory usage, run time, garbage collection of the global stack and stack shifts.

statistics(?Key,?Value)

This allows a program to gather various execution statistics. For each of the possible keys Key, Value is unified with a list of values, as follows:


global_stack
[size used,free]
This refers to the global stack, where compound terms are stored. The values are gathered before the list holding the answers is allocated.
local_stack
[size used,free]
This refers to the local stack, where recursive predicate environments are stored.
trail
[size used,free]
This refers to the trail stack, where conditional variable bindings are recorded.
choice
[size used,free]
This refers to the choicepoint stack, where partial states are stored for backtracking purposes.
core
memory
[size used,0]
These refer to the amount of memory actually allocated by the process.
heap
program
[size used,0]
These refer to the amount of memory allocated for compiled and interpreted clauses, symbol tables, and the like.
runtime
[since start of Prolog,since previous statistics] These refer to CPU time used while executing, excluding time spent garbage collecting, stack shifting, or in system calls.
walltime
[since start of Prolog,since previous statistics] These refer to absolute time elapsed.
garbage_collection
[no. of GCs,bytes freed,time spent]
stack_shifts
[no. of local shifts,no. of trail shifts,time spent]
atoms
[no. of atoms,bytes used,bytes free]
atom_garbage_collection
[no. of AGCs,bytes freed,time spent]

Times are in milliseconds, sizes of areas in bytes.

trimcore

Reclaims any dead clauses and predicates, defragmentizes Prolog's memory, and attempts to return any unused memory to the operating system. It is called automatically at every top level query.


Node:Meta Logic, Next:, Previous:State Info, Up:Built Intro

Meta-Logic

The predicates in this section are meta-logical and perform operations that require reasoning about the current instantiation of terms or decomposing terms into their constituents. Such operations cannot be expressed using predicate definitions with a finite number of clauses.

var(?X) [ISO]

Tests whether X is currently uninstantiated (var is short for variable). An uninstantiated variable is one which has not been bound to anything, except possibly another uninstantiated variable. Note that a compound term with some components which are uninstantiated is not itself considered to be uninstantiated. Thus the query

| ?- var(foo(X, Y)).

always fails, despite the fact that X and Y are uninstantiated.

nonvar(?X) [ISO]

Tests whether X is currently instantiated. This is the opposite of var/1.

ground(?X)

Tests whether X is completely instantiated, i.e. free of unbound variables. In this context, mutable terms are treated as nonground, so as to make ground/1 a monotone predicate.

atom(?X) [ISO]

Checks that X is currently instantiated to an atom (i.e. a non-variable term of arity 0, other than a number).

float(?X) [ISO]

Checks that X is currently instantiated to a float.

integer(?X) [ISO]

Checks that X is currently instantiated to an integer.

number(?X) [ISO]

Checks that X is currently instantiated to a number.

atomic(?X) [ISO]

Checks that X is currently instantiated to an atom or number.

simple(?X)

Checks that X is currently uninstantiated or instantiated to an atom or number.

compound(?X) [ISO]

Checks that X is currently instantiated to a compound term.

callable(?X)

Checks that X is currently instantiated to a term valid as a goal i.e. a compound term or an atom.

is_mutable(?X)

Checks that X is currently instantiated to a mutable term (see Modify Term).

functor(+Term,?Name,?Arity) [ISO]
functor(?Term,+Name,+Arity) [ISO]

The principal functor of term Term has name Name and arity Arity, where Name is either an atom or, provided Arity is 0, a number. Initially, either Term must be instantiated, or Name and Arity must be instantiated to, respectively, either an atom and an integer in [0,255] or an atomic term and 0. In the case where Term is initially uninstantiated, the result of the call is to instantiate Term to the most general term having the principal functor indicated.

arg(+ArgNo,+Term,?Arg) [ISO]

Arg is the argument ArgNo of the compound term Term. The arguments are numbered from 1 upwards, ArgNo must be instantiated to a positive integer and Term to a compound term.

+Term =.. ?List [ISO]
?Term =.. +List [ISO]

List is a list whose head is the atom corresponding to the principal functor of Term, and whose tail is a list of the arguments of Term. e.g.

| ?- product(0, n, n-1) =.. L.

L = [product,0,n,n-1]

| ?- n-1 =.. L.

L = [-,n,1]

| ?- product =.. L.

L = [product]

If Term is uninstantiated, then List must be instantiated either to a list of determinate length whose head is an atom, or to a list of length 1 whose head is a number. Note that this predicate is not strictly necessary, since its functionality can be provided by arg/3 and functor/3, and using the latter two is usually more efficient.

name(+Const,?CharList) [Obsolescent]
name(?Const,+CharList) [Obsolescent]

If Const is an atom or number, CharList is a list of the character codes of the characters comprising the name of Const. e.g.

| ?- name(product, L).

L = [112,114,111,100,117,99,116]

| ?- name(product, "product").

| ?- name(1976, L).

L = [49,57,55,54]

| ?- name('1976', L).

L = [49,57,55,54]

| ?- name((:-), L).

L = [58,45]

If Const is uninstantiated, CharList must be instantiated to a list of character codes. If CharList can be interpreted as a number, Const is unified with that number, otherwise with the atom whose name is CharList. E.g.

| ?- name(X, [58,45]).

X = :-

| ?- name(X, ":-").

X = :-

| ?- name(X, [49,50,51]).

X = 123

Note that there atoms are for which name(Const,CharList) is true, but which will not be constructed if name/2 is called with Const uninstantiated. One such atom is the atom '1976'. It is recommended that new programs use atom_codes/2 or number_codes/2, as these predicates do not have this inconsistency.

atom_codes(+Const,?CodeList) [ISO]
atom_codes(?Const,+CodeList) [ISO]

The same as name(Const,CodeList), but Const is constrained to be an atom.

number_codes(+Const,?CodeList) [ISO]
number_codes(?Const,+CodeList) [ISO]

The same as name(Const,CodeList), but Const is constrained to be a number.

atom_chars(+Const,?CharList) [ISO only]
atom_chars(?Const,+CharList) [ISO only]

Analogous to atom_codes/2, but CharList is a list of one-char atoms, rather than of character codes.

atom_chars(+Const,?CodeList) [SICStus only]
atom_chars(?Const,+CodeList) [SICStus only]

The same as atom_codes(Const,CharList).

number_chars(+Const,?CharList) [ISO only]
number_chars(?Const,+CharList) [ISO only]

Analogous to number_codes/2, but CharList is a list of one-char atoms, rather than of character codes.

number_chars(+Const,?CodeList) [SICStus only]
number_chars(?Const,+CodeList) [SICStus only]

The same as number_codes(Const,CharList).

char_code(+Char,?Code) [ISO]
char_code(?Char,+Code) [ISO]

Code is the character code of the one-char atom Char.

atom_length(+Atom,?Length) [ISO]

Length is the number of characters of the atom Atom.

atom_concat(+Atom1,+Atom2,?Atom12) [ISO]
atom_concat(?Atom1,?Atom2,+Atom12) [ISO]

The characters of the atom Atom1 concatenated with those of Atom2 are the same as the characters of atom Atom12. If the last argument is instantiated, nondeterministically enumerates all possible atom-pairs that concatenate to the given atom, e.g.

| ?- atom_concat(A, B, 'ab').

A = '',
B = ab ? ;

A = a,
B = b ? ;

A = ab,
B = '' ? ;

no

sub_atom(+Atom,?Before,?Length,?After,?SubAtom) [ISO]

The characters of SubAtom form a sublist of the characters of Atom, such that the number of characters preceding SubAtom is Before, the number of characters after SubAtom is After, and the length of SubAtom is Length. Capable of nondeterministically enumerating all sub-atoms and their all possible placements, e.g.

| ?- sub_atom(abrakadabra, Before, _, After, ab).

After = 9,
Before = 0 ? ;

After = 2,
Before = 7 ? ;

no

copy_term(?Term,?CopyOfTerm) [ISO]

CopyOfTerm is a renaming of Term, such that brand new variables have been substituted for all variables in Term. If any of the variables of Term have goals blocked on them, the copied variables will have copies of the goals blocked on them as well. Similarly, independent copies are substituted for any mutable terms in term. It behaves as if defined by:

copy_term(X, Y) :-
        assert('copy of'(X)),
        retract('copy of'(Y)).

The implementation of copy_term/2 conserves space by not copying ground subterms.


Node:Modify Term, Next:, Previous:Meta Logic, Up:Built Intro

Modification of Terms

One of the tenets of logic programming is that terms are immutable objects of the Herbrand universe, and the only sense in which they can be modified is by means of instantiating non-ground parts. There are, however, algorithms where destructive assignment is essential for performance. Although alien to the ideals of logic programming, this feature can be defended on practical grounds.

SICStus Prolog provides an abstract datatype and three operations for efficient backtrackable destructive assignment. In other words, any destructive assignments are transparently undone on backtracking. Modifications that are intended to survive backtracking must be done by asserting or retracting dynamic program clauses instead. Unlike previous releases of SICStus Prolog, destructive assignment of arbitrary terms is not allowed.

A mutable term is represented as a compound terms with a reserved functor: '$mutable'(Value,Timestamp) where Value is the current value and Timestamp is reserved for bookkeeping purposes [Aggoun & Beldiceanu 90].

Any copy of a mutable term created by copy_term/2, assert, retract, an internal database predicate, or an all solutions predicate, is an independent copy of the original mutable term. Any destructive assignment done to one of the copies will not affect the other copy.

The following operations are provided:

create_mutable(+Datum,-Mutable)

Mutable is a new mutable term with initial value Datum. Datum must not be an unbound variable.

get_mutable(?Datum,+Mutable)

Datum is the current value of the mutable term Mutable.

update_mutable(+Datum,+Mutable)

Updates the current value of the mutable term Mutable to become Datum. Datum must not be an unbound variable.

is_mutable(?Mutable)

Checks that Mutable is currently instantiated to a mutable term.

NOTE: the effect of unifying two mutables is undefined.


Node:Modify Prog, Next:, Previous:Modify Term, Up:Built Intro

Modification of the Program

The predicates defined in this section allow modification of dynamic predicates. Dynamic clauses can be added (asserted) or removed from the program (retracted).

For these predicates, the argument Head must be instantiated to an atom or a compound term, with an optional module prefix. The argument Clause must be instantiated either to a term Head :- Body or, if the body part is empty, to Head, with an optional module prefix. An empty body part is represented as true.

Note that a term Head :- Body must be enclosed in parentheses when it occurs as an argument of a compound term, as :- is a standard infix operator with precedence greater than 1000 (see Operators), e.g.:

| ?- assert((Head :- Body)).

Like recorded terms (see Database), the clauses of dynamic predicates have a unique implementation-defined identifier. Some of the predicates below have an additional argument which is this identifier. This identifier makes it possible to access clauses directly instead of requiring a normal database (hash-table) lookup.


assert(:Clause)
assert(:Clause,-Ref)

The current instance of Clause is interpreted as a clause and is added to the current interpreted program. The predicate concerned must currently be dynamic or undefined and the position of the new clause within it is implementation-defined. Ref is a database reference to the asserted clause. Any uninstantiated variables in the Clause will be replaced by new private variables, along with copies of any subgoals blocked on these variables (see Procedural).

asserta(:Clause) [ISO]
asserta(:Clause,-Ref)

Like assert/2, except that the new clause becomes the first clause for the predicate concerned.

assertz(:Clause) [ISO]
assertz(:Clause,-Ref)

Like assert/2, except that the new clause becomes the last clause for the predicate concerned.

clause(:Head,?Body) [ISO]
clause(:Head,?Body,?Ref)
clause(?Head,?Body,+Ref)

The clause (Head :- Body) exists in the current interpreted program, and its database reference is Ref. The predicate concerned must currently be dynamic. At the time of call, either Ref must be instantiated, or Head must be instantiated to an atom or a compound term. Thus clause/3 can have two different modes of use.

retract(:Clause) [ISO]

The first clause in the current interpreted program that matches Clause is erased. The predicate concerned must currently be dynamic. retract/1 may be used in a non-determinate fashion, i.e. it will successively retract clauses matching the argument through backtracking. If reactivated by backtracking, invocations of the predicate whose clauses are being retracted will proceed unaffected by the retracts. This is also true for invocations of clause/[2,3] for the same predicate. The space occupied by a retracted clause will be recovered when instances of the clause are no longer in use.

retractall(:Head)

Erases all clauses whose head matches Head, where Head must be instantiated to an atom or a compound term. The predicate concerned must currently be dynamic. The predicate definition is retained.

NOTE: all predicates mentioned above first look for a predicate that is visible in the module in which the call textually appears. If no predicate is found, a new dynamic predicate (with no clauses) is created automatically. It is recommended to declare as dynamic predicates for which clauses will be asserted.

abolish(:Spec) [ISO]
abolish(:Name,+Arity)

Abolishes the procedures specified by the generalized predicate spec Spec or Name/Arity. Name may be prefixed by a module name (see Module Spec). In iso execution mode only dynamic predicates can be abolished. In sicstus execution mode only built-in predicates cannot be abolished, the user-defined ones always can be, even when static.

erase(+Ref)

The dynamic clause or recorded term (see Database) whose database reference is Ref is effectively erased from the internal database or interpreted program.

instance(+Ref,?Term)

A (most general) instance of the dynamic clause or recorded term whose database reference is Ref is unified with Term.


Node:Database, Next:, Previous:Modify Prog, Up:Built Intro

Internal Database

The predicates described in this section were introduced in early implementations of Prolog to provide efficient means of performing operations on large quantities of data. The introduction of indexed dynamic predicates have rendered these predicates obsolete, and the sole purpose of providing them is to support existing code. There is no reason whatsoever to use them in new code.

These predicates store arbitrary terms in the database without interfering with the clauses which make up the program. The terms which are stored in this way can subsequently be retrieved via the key on which they were stored. Many terms may be stored on the same key, and they can be individually accessed by pattern matching. Alternatively, access can be achieved via a special identifier which uniquely identifies each recorded term and which is returned when the term is stored.


recorded(?Key,?Term,?Ref) [Obsolescent]

The internal database is searched for terms recorded under the key Key. These terms are successively unified with Term in the order they occur in the database. At the same time, Ref is unified with the database reference to the recorded item. If the key is instantiated to a compound term, only its principal functor is significant. If the key is uninstantiated, all terms in the database are successively unified with Term in the order they occur.

recorda(+Key,?Term,-Ref) [Obsolescent]

The term Term is recorded in the internal database as the first item for the key Key, where Ref is its database reference. The key must be given, and only its principal functor is significant. Any uninstantiated variables in the Term will be replaced by new private variables, along with copies of any subgoals blocked on these variables (see Procedural).

recordz(+Key,?Term,-Ref) [Obsolescent]

Like recorda/3, except that the new term becomes the last item for the key Key.

current_key(?KeyName,?KeyTerm) [Obsolescent]

KeyTerm is the most general form of the key for a currently recorded term, and KeyName is the name of that key. This predicate can be used to enumerate in undefined order all keys for currently recorded terms through backtracking.


Node:Blackboard Primitives, Next:, Previous:Database, Up:Built Intro

Blackboard Primitives

The predicates described in this section store arbitrary terms in a per-module repository known as the "blackboard". The main purpose of the blackboard was initially to provide a means for communication between branches executing in parallel, but the blackboard works equally well during sequential execution. The blackboard implements a mapping from keys to values. Keys are restricted to being atoms or integers in the range [-33554432, 33554431], whereas values are arbitrary terms. In contrast to the predicates described in the previous sections, a given key can map to at most a single term.

Each Prolog module maintains its own blackboard, so as to avoid name clashes if different modules happen to use the same keys. The "key" arguments of these predicates are subject to module name expansion, so the module name does not have to be explicitly given unless multiple Prolog modules are supposed to share a single blackboard.

The predicates below implement atomic blackboard actions.

bb_put(:Key, +Term)

A copy of Term is stored under Key. Any previous term stored under the same Key is simply deleted.

bb_get(:Key, ?Term)

If a term is currently stored under Key, a copy of it is unified with Term. Otherwise, bb_get/2 silently fails.

bb_delete(:Key, ?Term)

If a term is currently stored under Key, the term is deleted, and a copy of it is unified with Term. Otherwise, bb_delete/2 silently fails.

bb_update(:Key, ?OldTerm, ?NewTerm)

If a term is currently stored under Key and unifies with OldTerm, the term is replaced by a copy of NewTerm. Otherwise, bb_update/3 silently fails. This predicate provides an atomic swap operation.

The following example illustrates how these primitives may be used to implement a "maxof" predicate that finds the maximum value computed by some non-determinate goal, which may execute in parallel. We use a single key max. Note the technique of using bb_update/3 in a repeat-fail loop, since other execution branches may be competing for updating the value, and we only want to store a new value if it is greater than the old value.

We assume that Goal does not produce any "false" solutions that would be eliminated by cuts in a sequential execution. Thus, Goal may need to include redundant checks to ensure that its solutions are valid, as discussed above.

maxof(Value, Goal, _) :-
        bb_put(max, -1),                % initialize max-so-far
        call(Goal),
        update_max(Value),
        fail.
maxof(_, _, Max) :-
        bb_delete(max, Max),
        Max > 1.

update_max(New):-
        repeat,
          bb_get(max, Old),
          compare(C, Old, New),
          update_max(C, Old, New), !.

update_max(<, Old, New) :- bb_update(max, Old, New).
update_max(=, _, _).
update_max(>, _, _).


Node:All Solutions, Next:, Previous:Blackboard Primitives, Up:Built Intro

All Solutions

When there are many solutions to a problem, and when all those solutions are required to be collected together, this can be achieved by repeatedly backtracking and gradually building up a list of the solutions. The following built-in predicates are provided to automate this process.

Note that the Goal argument to the predicates listed below is called as if by call/1 at runtime. Thus if Goal is complex and if performance is an issue, define an auxiliary predicate which can then be compiled, and let Goal call it.

setof(?Template,:Goal,?Set) [ISO]

Read this as "Set is the set of all instances of Template such that Goal is satisfied, where that set is non-empty". The term Goal specifies a goal or goals as in call(Goal) (see Control). Set is a set of terms represented as a list of those terms, without duplicates, in the standard order for terms (see Term Compare). If there are no instances of Template such that Goal is satisfied then the predicate fails.

The variables appearing in the term Template should not appear anywhere else in the clause except within the term Goal. Obviously, the set to be enumerated should be finite, and should be enumerable by Prolog in finite time. It is possible for the provable instances to contain variables, but in this case the list Set will only provide an imperfect representation of what is in reality an infinite set.

If there are uninstantiated variables in Goal which do not also appear in Template, then a call to this built-in predicate may backtrack, generating alternative values for Set corresponding to different instantiations of the free variables of Goal. (It is to cater for such usage that the set Set is constrained to be non-empty.) Two instantiations are different iff no renaming of variables can make them literally identical. For example, given the clauses:

likes(bill, cider).
likes(dick, beer).
likes(harry, beer).
likes(jan, cider).
likes(tom, beer).
likes(tom, cider).

the query

| ?- setof(X, likes(X,Y), S).

might produce two alternative solutions via backtracking:

S = [dick,harry,tom],
Y = beer ? ;

S = [bill,jan,tom],
Y = cider ? ;

The query:

| ?- setof((Y,S), setof(X, likes(X,Y), S), SS).

would then produce:

SS = [(beer,[dick,harry,tom]),(cider,[bill,jan,tom])]

Variables occurring in Goal will not be treated as free if they are explicitly bound within Goal by an existential quantifier. An existential quantification is written:

Y^Q

meaning "there exists a Y such that Q is true", where Y is some Prolog variable.

For example:

| ?- setof(X, Y^(likes(X,Y)), S).

would produce the single result:

S = [bill,dick,harry,jan,tom]

in contrast to the earlier example.

Note that in iso execution mode, only outermost existential quantification is accepted, i.e. if the Goal argument is of form V1 ^ ... ^ N ^ SubGoal. In sicstus execution mode existential quantification is handled also deeper inside Goal.

bagof(?Template,:Goal,?Bag) [ISO]

This is exactly the same as setof/3 except that the list (or alternative lists) returned will not be ordered, and may contain duplicates. The effect of this relaxation is to save a call to sort/2, which is invoked by setof/3 to return an ordered list.

?X^:P

The all solution predicates recognize this as meaning "there exists an X such that P is true", and treats it as equivalent to P (see Control). The use of this explicit existential quantifier outside the setof/3 and bagof/3 constructs is superfluous and discouraged.

findall(?Template,:Goal,?Bag) [ISO]

Bag is a list of instances of Template in all proofs of Goal found by Prolog. The order of the list corresponds to the order in which the proofs are found. The list may be empty and all variables are taken as being existentially quantified. This means that each invocation of findall/3 succeeds exactly once, and that no variables in Goal get bound. Avoiding the management of universally quantified variables can save considerable time and space.

findall(?Template,:Goal,?Bag,?Remainder)

Same as findall/3, except Bag is the list of solution instances appended with Remainder, which is typically unbound.


Node:Coroutining, Next:, Previous:All Solutions, Up:Built Intro

Coroutining

The coroutining facility can be accessed by a number of built-in predicates. This makes it possible to use coroutines in a dynamic way, without having to rely on block declarations:

when(+Condition,:Goal)

Blocks Goal until the Condition is true, where Condition is a Prolog goal with the restricted syntax:

nonvar(X)
ground(X)
?=(X,Y)
Condition,Condition
Condition;Condition

For example:

| ?- when(((nonvar(X);?=(X,Y)),ground(T)), process(X,Y,T)).

freeze(?X,:Goal)

Blocks Goal until nonvar(X) (see Meta Logic) holds. This is defined as if by:

freeze(X, Goal) :- when(nonvar(X), Goal).

or

:- block freeze(-, ?).
freeze(_, Goal) :- Goal.

frozen(-Var,?Goal)

If some goal is blocked on the variable Var, or Var has attributes that can be interpreted as a goal (see Attributes), then that goal is unified with Goal. If no goals are blocked, Goal is unified with the atom true. If more than one goal is blocked, a conjunction is unified with Goal.

dif(?X,?Y)

Constrains X and Y to represent different terms i.e. to be non-unifiable. Calls to dif/2 either succeed, fail, or are blocked depending on whether X and Y are sufficiently instantiated. It is defined as if by:

dif(X, Y) :- when(?=(X,Y), X\==Y).

call_residue(:Goal,?Residue)

The Goal is executed as if by call/1. If after the execution there are still some subgoals of Goal that are blocked on some variables, then Residue is unified with a list of VariableSet-Goal pairs, and those subgoals are no longer blocked on any variables. Otherwise, Residue is unified with the empty list [].

VariableSet is a set of variables such that when any of the variables is bound, Goal gets unblocked. Usually, a goal is blocked on a single variable, in which case VariableSet is a singleton.

Goal is an ordinary goal, sometimes module prefixed. For example:

| ?- call_residue((dif(X,f(Y)), X=f(Z)), Res).

X = f(Z),
Res = [[Y,Z]-(prolog:dif(f(Z),f(Y)))]


Node:Debug Pred, Next:, Previous:Coroutining, Up:Built Intro

Debugging

Debugging predicates are not available in runtime systems.

unknown(?OldState,?NewState)

OldState is the current state of the "Action on unknown predicates" flag, and sets the flag to NewState. This flag determines whether or not the system is to catch calls to undefined predicates (see Undefined Predicates), when user:unknown_predicate_handler/3 cannot handle the goal. The possible states of the flag are:

trace
Causes calls to undefined predicates to be reported and the debugger to be entered at the earliest opportunity. Not available in runtime systems.
fail
Causes calls to such predicates to fail.
warning
Causes calls to such predicates to display a warning message and then fail.
error
Causes calls to such predicates to raise an exception (the default). See Exception.

debug

The debugger is switched on in leap mode. See Basic Debug.

trace

The debugger is switched on in creep mode. See Basic Debug.

zip

The debugger is switched on in zip mode. See Basic Debug.

nodebug
notrace
nozip

The debugger is switched off. See Basic Debug.

leash(+Mode)

Leashing Mode is set to Mode. See Basic Debug.

spy :Spec

Plain spypoints are placed on all the predicates given by Spec. See Plain Spypoint.

spy(:Spec, :Conditions)

Spypoints with condition Conditions are placed on all the predicates given by Spec. See Breakpoint Predicates.

nospy :Spec

All spypoints (plain and conditional) are removed from all the predicates given by Spec. See Plain Spypoint.

nospyall

Removes all the spypoints (including the generic ones) that have been set.

debugging

Displays information about the debugger. See Basic Debug.

add_breakpoint(:Conditions, ?BID)

Creates a breakpoint with Conditions and with identifier BID. See Breakpoint Predicates.

current_breakpoint(:Conditions, ?BID, ?Status, ?Kind)

There is a breakpoint with conditions Conditions, identifier BID, enabledness Status, and kind Kind. See Breakpoint Predicates.

remove_breakpoints(+BIDs)
disable_breakpoints(+BIDs)
enable_breakpoints(+BIDs)

Removes, disables or enables the breakpoints specified by BIDs. See Breakpoint Predicates.

execution_state(:Tests)

Tests are satisfied in the current state of the execution.

execution_state(+FocusConditions, :Tests)

Tests are satisfied in the state of the execution pointed to by FocusConditions.

debugger_command_hook(+Char,?Actions) [Hook]
user:debugger_command_hook(+Char,?Actions)

Allows the interactive debugger to be extended with user-defined commands. See Debug Commands.

error_exception(+Exception) [Hook]
user:error_exception(+Exception)

Tells the debugger to enter trace mode on certain exceptions. See Breakpoints.


Node:Profiling, Next:, Previous:Debug Pred, Up:Built Intro

Execution Profiling

Execution profiling is a common aid for improving software performance. The SICStus Prolog compiler has the capability of instrumenting compiled code with counters which are initially zero and incremented whenever the flow of control passes a given point in the compiled code. This way the number of calls, backtracks, choicepoints created, etc., can be counted for the instrumented predicates, and an estimate of the time spent in individual clauses and disjuncts can be calculated.

Gauge is a graphical user interface for inspecting execution profiles. It is available as a library module (see Gauge Intro).

The original version of the profiling package was written by M.M. Gorlick and C.F. Kesselman at the Aerospace Corporation [Gorlick & Kesselman 87].

Only compiled code can be instrumented. To get an execution profile of a program, the compiler must first be told to produce instrumented code. This is done by issuing the query:

| ?- prolog_flag(compiling,_,profiledcode).

after which the program to be analyzed can be compiled as usual. Any new compiled code will be instrumented while the compilation mode flag has the value profiledcode.

The profiling data is generated by simply running the program. The predicate profile_data/4 (see below) makes available a selection of the data as a Prolog term. The predicate profile_reset/1 zeroes the profiling counters for a selection of the currently instrumented predicates.

profile_data(:Spec,?Selection,?Resolution,-Data)

Data is profiling data collected from the predicates covered by the generalized predicate spec Spec.

The Selection argument determines the kind of profiling data to be collected. If uninstantiated, the predicate will backtrack over its possible values, which are:

calls
All instances of entering a clause by a procedure call are counted. This is equivalent to counting all procedure calls that have not been determined to fail by indexing on the first argument.
backtracks
All instances of entering a clause by backtracking are counted.
choice_points
All instances of creating a choicepoint are counted. This occurs, roughly, when the implementation determines that there are more than one possibly matching clauses for a procedure call, and when a disjunction is entered.
shallow_fails
Failures in the "if" part of if-then-else statements, and in the "guard" part of guarded clauses, are counted as shallow failures. See If-Then-Else.
deep_fails
Any failures that do not classify as shallow as above are counted as deep failures. The reason for distinguishing shallow and deep failures is that the former are considerably cheaper to execute than the latter.
execution_time
The execution time for the selected predicates, clauses, or disjuncts is estimated in artificial units.

The Resolution argument determines the level of resolution of the profiling data to be collected. If uninstantiated, the predicate will backtrack over its possible values, which are:

predicate
Data is a list of Module:PredName-Count, where Count is a sum of the corresponding counts per clause.
clause
Data is a list of Module:ClauseName-Count, where Count includes counts for any disjunctions occurring inside that clause. Note, however, that the selections calls and backtracks do not include counts for disjunctions.
all
Data is a list of Module:InternalName-Count. This is the finest resolution level, counting individual clauses and disjuncts.

Above, PredName is a predicate spec, ClauseName is a compound term PredName/ClauseNumber, and InternalName is either
ClauseName--corresponding to a clause, or
(ClauseName-DisjNo)/Arity/AltNo--corresponding to a disjunct.

profile_reset(:Spec)

Zeroes all counters for predicates covered by the generalized predicate spec Spec.


Node:Misc Pred, Previous:Profiling, Up:Built Intro

Miscellaneous

?X = ?Y [ISO]

Defined as if by the clause Z=Z.; i.e. X and Y are unified.

?X \= ?Y [ISO]

The same as \+ X = Y; i.e. X and Y are not unifiable.

unify_with_occurs_check(?X, ?Y) [ISO]

True if X and Y unify to a finite (acyclic) term. Runs in almost linear time.

length(?List,?Length)

If List is instantiated to a list of determinate length, then Length will be unified with this length.

If List is of indeterminate length and Length is instantiated to an integer, then List will be unified with a list of length Length. The list elements are unique variables.

If Length is unbound then Length will be unified with all possible lengths of List.

numbervars(?Term,+N,?M)

Unifies each of the variables in term Term with a special term, so that write(Term) (or writeq(Term)) (see Term I/O) prints those variables as (A + (i mod 26))(i/26) where i ranges from N to M-1. N must be instantiated to an integer. If it is 0 you get the variable names A, B, ..., Z, A1, B1, etc. This predicate is used by listing/[0,1] (see State Info).

halt [ISO]

Causes Prolog to exit back to the shell. (In recursive calls to Prolog from C, this predicate will return back to C instead.)

halt(+Code) [ISO]

Causes the Prolog process to immediately exit back to the shell with the integer return code Code, even if it occurs in a recursive call from C.

op(+Precedence,+Type,+Name) [ISO]

Declares the atom Name to be an operator of the stated Type and Precedence (see Operators). Name may also be a list of atoms in which case all of them are declared to be operators. If Precedence is 0 then the operator properties of Name (if any) are cancelled.

current_op(?Precedence,?Type,?Op) [ISO]

The atom Op is currently an operator of type Type and precedence Precedence. Neither Op nor the other arguments need be instantiated at the time of the call; i.e. this predicate can be used to generate as well as to test.

break

Invokes a recursive top-level. See Nested. (This predicate is not available in runtime systems.)

abort

Aborts the current execution. See Nested. (In recursive calls to Prolog from C, this predicate will return back to C instead.)

save_files(+SourceFiles, +File)

Any module declarations, predicates, multifile clauses, or directives encountered in SourceFiles are saved in object format into the file File. Source file information as provided by source_file/[1,2] for the relevant predicates and modules is also saved.

If File does not have an explicit suffix, the suffix .po will be appended to it. SourceFiles should denote a single file or a list of files. File can later be loaded by load_files/[1,2], at which time any saved directives will be re-executed. If any of the SourceFiles declares a module, File too will behave as a module-file and export the predicates listed in the first module declaration encountered in SourceFiles. See Saving.

save_modules(+Modules, +File)

The module declarations, predicates, multifile clauses and initializations belonging to Modules are saved in object format into the file File. Source file information and arbitrary directives are not saved.

If File does not have an explicit suffix, the suffix .po will be appended to it. Modules should denote a single module or a list of modules. File can later be loaded by load_files/[1,2] and will behave as a module-file and export any predicates exported by the first module in Modules. See Saving.

save_predicates(:Spec, +File)

The predicates specified by the generalized predicate spec Spec are saved in object format into the file File. Source file information and directives are not saved. Thus, this predicate is intended for saving data represented as tables of dynamic facts, not for saving static code.

If File does not have an explicit suffix, the suffix .po will be appended to it. File can later be loaded by load_files/[1,2]. See Saving.

save_program(+File)
save_program(+File, :Goal)

The system saves the program state into file File. When the program state is restored, Goal is executed. Goal defaults to true. See Saving.

restore(+File)

The system is returned to the program state previously saved to file File with start-up goal Goal. restore/1 may succeed, fail or raise an exception depending on Goal. See Saving.

reinitialise

This predicate can be used to force the reinitialization behavior to take place at any time. When SICStus Prolog is reinitialized it:

(In recursive calls to Prolog from C, this predicate will return back to C instead.)
garbage_collect

Performs a garbage collection of the global stack immediately.

garbage_collect_atoms

Performs a garbage collection of the atoms immediately.

gc

Enables garbage collection of the global stack (the default).

nogc

Disables garbage collection of the global stack.

prompt(?Old,?New)

The sequence of characters (prompt) which indicates that the system is waiting for user input is represented as an atom, and unified with Old; the atom bound to New specifies the new prompt. In particular, the goal prompt(X, X) unifies the current prompt with X, without changing it. Note that this predicate only affects the prompt given when a user's program is trying to read from the standard input stream (e.g. by calling read/1). Note also that the prompt is reset to the default |: on return to top-level.

version

Displays the introductory messages for all the component parts of the current system.

Prolog will display its own introductory message when initially run and on reinitialization by calling version/0. If this message is required at some other time it can be obtained using this predicate which displays a list of introductory messages; initially this list comprises only one message (Prolog's), but you can add more messages using version/1. (This predicate is not available in runtime systems.)

version(+Message)

Appends Message to the end of the message list which is output by version/0. Message must be an atom. (This predicate is not available in runtime systems.)

The idea of this message list is that, as systems are constructed on top of other systems, each can add its own identification to the message list. Thus version/0 should always indicate which modules make up a particular package. It is not possible to remove messages from the list.

help [Hookable]

Displays basic information, or a user defined help message. It first calls user:user_help/0, and only if that call fails is a default help message printed on the current output stream. (This predicate is not available in runtime systems.)

user_help [Hook]
user:user_help

This may be defined by the user to print a help message on the current output stream.


Node:Mixing C and Prolog, Next:, Previous:Built Intro, Up:Top

Mixing C and Prolog

SICStus Prolog provides a bi-directional, procedural interface for program parts written in C and Prolog. The C side of the interface defines a number of functions and macros for various operations. On the Prolog side, you have to supply declarations specifying the names and argument/value types of C functions being called as Prolog predicates. These declarations are used by the predicate load_foreign_resource/1, which performs the actual binding of C functions to Prolog predicates.

In most cases, the argument/value type declaration suffice for making the necessary conversions of data automatically as they are passed between C and Prolog. However, it is possible to declare the type of an argument to be a Prolog term, in which case the receiving function will see it as a "handle" object, called an SP_term_ref, for which access functions are provided.

The C support routines are available in a development system as well as in runtime systems. The support routines include:


Node:Notes, Next:, Previous:Mixing C and Prolog, Up:Mixing C and Prolog

Notes


ANSI Conformance
Throughout this chapter, void * in the function definitions may be changed to char * on non ANSI conforming C compilers.
The SP_PATH variable
It is normally not necessary to set this environment variable, but its value will be used at runtime if no explicit boot path is given when initializing a runtime or development System. In this chapter, the environment variable SP_PATH is used as a shorthand for the SICStus Prolog installation directory, whose default UNIX location is /usr/local/lib/sicstus-3.8). See Environment Variables.
Definitions and declarations
Type definitions and function declarations for the interface are found in the header file <sicstus/sicstus.h>.
Error Codes

The value of many support functions is a return code which is one of SP_SUCCESS for success, SP_FAILURE for failure, SP_ERROR if an error condition occurred. In particular, uncaught exceptions resulting from calls from C to Prolog raise an error condition. In error situations, the macro SP_errno will return a value describing the error condition:

int SP_errno

The function SP_error_message returns a pointer to the diagnostic message corresponding to a specified error number:

char *SP_error_message(int errno)

Wide Characters
The foreign interface supports wide characters. Whenever a sequence of possibly wide character codes is to be passed to or from a C function it is encoded as a sequence of bytes, using the so called internal encoding of SICStus Prolog, the UTF-8 encoding; see WCX Concepts. Unless noted otherwise the encoded form is terminated by a NULL byte. This sequence of bytes will be called an encoded string, representing the given sequence of character codes. Note that it is a property of the UTF-8 encoding that it does not change ASCII character code sequences.

If a foreign function is specified to return an encoded string, an exception will be raised if, on return to Prolog, the actual string is ill-formed (is not a valid sequence of UTF-8 encoded characters). The exception raised is representation_error(...,...,mis_encoded_string).


Node:Calling C, Next:, Previous:Notes, Up:Mixing C and Prolog

Calling C from Prolog

Functions written in the C language may be called from Prolog using an interface in which automatic type conversions between Prolog terms and common C types are declared as Prolog facts. Calling without type conversion can also be specified, in which case the arguments and values are passed as SP_term_refs. This interface is partly modeled after Quintus Prolog.

The functions installed using this foreign language interface may invoke Prolog code and use the support functions described in the other sections of this chapter.

Functions, or their equivalent, in any other language having C compatible calling conventions may also be interfaced using this interface. When referring to C functions in the following, we also include such other language functions. Note however that a C compiler is needed since a small amount of glue code (in C) must be generated for interfacing purposes.


Node:Foreign Resources, Next:, Previous:Calling C, Up:Calling C

Foreign Resources

A foreign resource is a set of C functions, defined in one or more files, installed as an atomic operation. The name of a foreign resource, the resource name, is an atom, which should uniquely identify the resource. Thus, two foreign resources with the same name cannot be installed at the same time.

For each foreign resource, a foreign_resource/2 fact is used to declare the interfaced functions. For each of these functions, a foreign/[2,3] fact is used to specify conversions between predicate arguments and C-types. These conversion declarations are used for creating the necessary interface between Prolog and C.

The functions making up the foreign resource, the automatically generated glue code, and any libraries, are compiled and linked, using the program splfr (see The splfr utility) or link_foreign_resource/6 (see Interface Predicates), to form a linked foreign resource. A linked foreign resource exists in two different flavors, static and dynamic. A static resource is simply a relocatable object file containing the foreign code. A dynamic resource is a shared library (.so under most UNIX dialects, .dll under Windows) which is loaded into the Prolog executable at runtime.

Foreign resources can be linked into the Prolog executable either when the executable is built (pre-linked), or at runtime. Pre-linking can be done using static or dynamic resources. Runtime-linking can only be done using dynamic resources. Dynamic resources can also be unlinked.

In all cases, the declared predicates are installed by the built-in predicate load_foreign_resource/1. The resource name of a linked foreign resource is derived from its filename by deleting any leading path and the suffix. If the resource was pre-linked, only the predicate names are bound, otherwise runtime-linking is attempted (using dlopen(), LoadLibrary(), or similar).

Static and pre-linked resources are not supported under Windows. See Windows notes, for more information.


Node:Conversion Declarations, Next:, Previous:Foreign Resources, Up:Calling C

Conversion Declarations

Conversion declaration predicates:

foreign_resource(+ResourceName,+Functions) [Hook]

Specifies that a set of foreign functions, to be called from Prolog, are to be found in the resource named by ResourceName. Functions is a list of functions exported by the resource. Only functions that are to be called from Prolog and optionally one init function and one deinit function should be listed. The init and deinit functions are specified as init(Function) and deinit(Function) respectively (see Init and Deinit Functions). This predicate should be defined entirely in terms of facts (unit clauses) and will be called in the relevant module, i.e. not necessarily in the user module. For example:

foreign_resource('terminal', [scroll,pos_cursor,ask]).

specifies that functions scroll(), pos_cursor() and ask() are to be found in the resource terminal.

foreign(+CFunctionName, +Predicate) [Hook]
foreign(+CFunctionName, +Language, +Predicate) [Hook]

Specify the Prolog interface to a C function. Language is at present constrained to the atoms c and java. CFunctionName is the name of a C function. Predicate specifies the name of the Prolog predicate that will be used to call CFunction(). Predicate also specifies how the predicate arguments are to be translated into the corresponding C arguments. These predicates should be defined entirely in terms of facts (unit clauses) and will be called in the relevant module, i.e. not necessarily in the user module. For example:

foreign(pos_cursor, c, move_cursor(+integer, +integer)).

The above example says that the C function pos_cursor() has two integer value arguments and that we will use the predicate move_cursor/2 to call this function. A goal move_cursor(5, 23) would translate into the C call pos_cursor(5,23);.

The third argument of the predicate foreign/3 specifies how to translate between Prolog arguments and C arguments. A call to a foreign predicate will raise an exception if an input arguments is uninstantiated (instantiation_error/2) or has the wrong type (type_error/4) or domain (domain_error/4). The call will fail upon return from the function if the output arguments do not unify with the actual arguments.

The available conversions are listed in the next subsection.


Node:Conversions, Next:, Previous:Conversion Declarations, Up:Calling C

Conversions between Prolog Arguments and C Types

The following table lists the possible values for the arguments in the predicate specification of foreign/[2,3]. The value declares which conversion between corresponding Prolog argument and C type will take place. Note that the term chars below refers to a list of character codes, rather than to one-char atoms.

Prolog: +integer
C: long
The argument should be a number. It is converted to a C long and passed to the C function.
Prolog: +float
C: double
The argument should be a number. It is converted to a C double and passed to the C function.
Prolog: +atom
C: unsigned long
The argument should be an atom. Its canonical representation is passed to the C function.
Prolog: +chars
C: char *
The argument should be a list of character codes. The C function will be passed the address of an array with the encoded string representation of these characters. The array is subject to reuse by other support functions, so if the value is going to be used on a more than temporary basis, it must be moved elsewhere.
Prolog: +string
C: char *
The argument should be an atom. The C function will be passed the address of an encoded string representing the characters of the atom. The C function should not overwrite the string.
Prolog: +string(N)
C: char *
The argument should be an atom. The encoded string representing the atom will be copied into a newly allocated buffer. The string will be truncated (at wide character boundary) if it is longer than N bytes. The string will be blank padded on the right if it is shorter than N bytes. The C function will be passed the address of the buffer. The C function may overwrite the buffer, but should not assume that it remains valid after returning.
Prolog: +address
C: void *
The argument should be an integer which should be a valid second argument to SP_put_address() (see Creating Prolog Terms). The value passed will be a void * pointer.
Prolog: +address(TypeName)
C: TypeName *
The argument should be an integer which should be a valid second argument to SP_put_address() (see Creating Prolog Terms). The value passed will be a TypeName * pointer.
Prolog: +term
C: SP_term_ref
The argument could be any term. The value passed will be the internal representation of the term.
Prolog: -integer
C: long *
The C function is passed a reference to an uninitialized long. The value returned will be converted to a Prolog integer.
Prolog: -float
C: double *
The C function is passed a reference to an uninitialized double. The value returned will be converted to a Prolog float.
Prolog: -atom
C: unsigned long *
The C function is passed a reference to an uninitialized unsigned long. The value returned should be the canonical representation of a Prolog atom.
Prolog: -chars
C: char **
The C function is passed the address of an uninitialized char *. The returned encoded string will be converted to a Prolog list of character codes.
Prolog: -string
C: char **
The C function is passed the address of an uninitialized char *. The returned encoded string will be converted to a Prolog atom. Prolog will copy the string to a safe place, so the memory occupied by the returned string may be reused during subsequent calls to foreign code.
Prolog: -string(N)
C: char *
The C function is passed a reference to a character buffer large enough to store an N bytes. The C function is expected to fill the buffer with an encoded string of N bytes (not NULL-terminated). This encoded string will be stripped of trailing blanks and converted to a Prolog atom.
Prolog: -address
C: void **
The C function is passed the address of an uninitialized void *. The returned value, which should be a valid second argument to SP_put_address() (see Creating Prolog Terms), will be converted to a Prolog integer.
Prolog: -address(TypeName)
C: TypeName **
The C function is passed the address of an uninitialized TypeName *. The returned value, which should be a valid second argument to SP_put_address() (see Creating Prolog Terms), will be converted to a Prolog integer.
Prolog: -term
C: SP_term_ref
The C function is passed a new SP_term_ref, and is expected to set its value to a suitable Prolog term. Prolog will try to unify the value with the actual argument.
Prolog: [-integer]
C: long F()
The C function should return a long. The value returned will be converted to a Prolog integer.
Prolog: [-float]
C: double F()
The C function should return a double. The value returned will be converted to a Prolog float.
Prolog: [-atom]
C: unsigned long F()
The C function should return an unsigned long. The value returned must be the canonical representation of a Prolog atom.
Prolog: [-chars]
C: char *F()
The C function should return a char *. The returned encoded string will be converted to a Prolog list of character codes.
Prolog: [-string]
C: char *F()
The C function should return a char *. The returned encoded string will be converted to a Prolog atom. Prolog will copy the string to a safe place, so the memory occupied by the returned string may be reused during subsequent calls to foreign code.
Prolog: [-string(N)]
C: char *F()
The C function should return a char *. The first N bytes of the encoded string (not necessarily NULL-terminated) will be copied and the copied string will be stripped of trailing blanks. The stripped string will be converted to a Prolog atom. C may reuse or destroy the string buffer during later calls.
Prolog: [-address]
C: void *F()
The C function should return a void *. The returned value, which should be a valid second argument to SP_put_address() (see Creating Prolog Terms), will be converted to a Prolog integer.
Prolog: [-address(TypeName)]
C: TypeName *F()
The C function should return a TypeName *. The returned value, which should be a valid second argument to SP_put_address() (see Creating Prolog Terms), will be converted to a Prolog integer.
Prolog: [-term]
C: SP_term_ref F()
The C function should return an SP_term_ref. Prolog will try to unify its value with the actual argument.


Node:Interface Predicates, Next:, Previous:Conversions, Up:Calling C

Interface Predicates

link_foreign_resource(+Resource,+SourceFile,+Option,+CFiles,+ObjectFiles,+Libraries)

Builds a linked foreign resource, using the splfr utility. Option can be either dynamic or static as described in the alternative form shown below. The Resource argument is an unsuffixed filename of a linked foreign resource. This predicate is not available in runtime systems.

load_foreign_resource(:Resource)

Unless a foreign resource with the same name as Resource has been statically linked, the linked foreign resource specified by Resource is linked into the Prolog load image. In both cases, the predicates defined by Resource are installed, and any init function is called. Dynamic linking is not possible if the foreign resource was linked using the +static option.

If a resource with the same name has been previously loaded, it will be unloaded as if unload_foreign_resource(Resource) was called, before Resource is loaded.

unload_foreign_resource(:Resource)

Any deinit function associated with Resource is called, and the predicates defined by Resource are uninstalled. If Resource has been dynamically linked, it is unlinked from the Prolog load image.

The following predicates are provided for backwards compatibility and should be avoided in new code:

foreign_file(+File,+Functions) [Hook,Obsolescent]

Specifies that a set of foreign functions, to be called from Prolog, are to be found in File. This predicate is only called from load_foreign_files/2.

load_foreign_files(:ObjectFiles,+Libraries) [Hookable,Obsolescent]

A resource name is derived from the first file name in ObjectFiles by stripping off the suffix. If this resource has been statically linked, the predicates defined by it are installed; otherwise, a linked foreign resource containing the declared functions is created and loaded. Not available in runtime systems.


Node:The splfr utility, Next:, Previous:Interface Predicates, Up:Calling C

The splfr utility

The splfr utility is used to create foreign resources (see Foreign Resources). splfr reads terms from a Prolog file, applying op declarations and extracting any foreign_resource/2 fact with first argument matching the resource name and all foreign/[2,3] facts. Based on this information, it generates the necessary glue code, and combines it with any additional C or object files provided by the user into a linked foreign resource. The output filename will be the resource name with a suitable extension.

splfr is invoked as

% splfr [ Option | InputFile ] ...

The input to splfr can be divided into Options and InputFiles and they can be arbitrarily mixed on the command line. Anything not interpreted as an option will be interpreted as an input file. Exactly one of the input files should be a Prolog file. The following options are available:

--help
Prints out a summary of all options.
-v
--verbose
Print detailed information about each step in the compilation/linking sequence.
-version
Prints out the version number of splfr.
--resource=ResourceName
Specify the resource's name. This defaults to the basename of the Prolog source file found on the command line.
--manual
Do not generate any glue code. This option can only be used when the interface code is generated manually as described in Runtime Utilities.
-S
--static
Create a statically linked foreign resource instead of a dynamically linked shared object (which is the default). A statically linked foreign resource is a single object file which can be pre-linked into a Prolog system. Only available under UNIX. See also the spld utility, The spld utility.
--keep
Keep temporary files and interface code and rename them to human-readable names. Not intended for the casual user, but useful if you want to know exactly which glue code is generated.
--import
Creates a import library for this resource. Necessary if you want to link external code against the resource. (Win32 only.)
--cflag=CFlags
CFlags is a comma-separated list of C-compiler options which will be separated at the commas and sent to the C-compiler passes.

The key input to splfr is the SourceFile. The contents of this file determines how the foreign resource's interface will look like. When the source-file is read in, foreign_resource/2 facts with first argument matching the name of this resource (i.e. ResourceName) is extracted together with all foreign/[2,3] facts.


Node:Init and Deinit Functions, Next:, Previous:The splfr utility, Up:Calling C

Init and Deinit Functions

An init function and/or a deinit function can be declared by foreign_resource/2. If this is the case, these functions should have the prototype:

void FunctionName (int when)

The init function is called by load_foreign_resource/1 after the resource has been loaded and the interfaced predicates have been installed.

The deinit function is called by unload_foreign_resource/1 before the interfaced predicates have been uninstalled and the resource has been unloaded.

The init and deinit functions may use the C-interface to call Prolog etc.

Foreign resources are unloaded before saving states, and reloaded afterwards or when the saved state is restored; see Saving. Foreign resources are also unloaded when exiting Prolog execution. The parameter when reflects the context of the (un)load_foreign_resource/1 and is set as follows for init functions:

SP_WHEN_EXPLICIT
Explicit call to load_foreign_resource/1.
SP_WHEN_RESTORE
Resource is reloaded after save or restore.

For deinit functions:

SP_WHEN_EXPLICIT
Explicit call to unload_foreign_resource/1.
SP_WHEN_SAVE
Resource is unloaded before save.
SP_WHEN_EXIT
Resource is unloaded before exiting Prolog.


Node:Creating the Linked Foreign Resource, Previous:Init and Deinit Functions, Up:Calling C

Creating the Linked Foreign Resource

Suppose we have a Prolog source file ex.pl containing:

foreign(f1, p1(+integer,[-integer])).
foreign(f2, p2(+integer,[-integer])).
foreign_resource(ex, [f1,f2]).
:- load_foreign_resource(ex).

and a C source file ex.c with definitions of the functions f1 and f2, both returning long and having a long as only parameter. The conversion declarations in ex.pl state that these functions form the foreign resource ex.

To create the linked foreign resource, simply type (to Prolog):

| ?- link_foreign_resource(ex,'ex.pl',dynamic,['ex.c'],[],[]).

or alternatively (to the Shell):

% splfr ex.pl ex.c

The linked foreign resource ex.so (file suffix .so is system dependent) has been created. It will be dynamically linked by the directive :- load_foreign_resource(ex). when the file ex.pl is loaded. Linked foreign resources can also be created manually (see Runtime Utilities).

Dynamic linking of foreign resources can also be used by Runtime Systems. On some platforms, however, the executable must not be stripped for dynamic linking to work, i.e. its symbol table must remain.


Node:Support, Next:, Previous:Calling C, Up:Mixing C and Prolog

Support Functions

The support functions include functions to manipulate SP_term_refs, functions to convert data between the basic C types and Prolog terms, functions to test whether a term can be converted to a specific C type, and functions to unify or compare two terms.


Node:Creating and Manipulating SP_term_refs, Next:, Previous:Support, Up:Support

Creating and Manipulating SP_term_refs

Normally, C functions only have indirect access to Prolog terms via SP_term_refs. C functions may receive arguments as unconverted Prolog terms, in which case the actual arguments received will have the type SP_term_ref. Also, a C function may return an unconverted Prolog term, in which case it must create an SP_term_ref. Finally, any temporary Prolog terms created by C code must be handled as SP_term_refs.

SP_term_refs are motivated by the fact that SICStus Prolog's memory manager must have a means of reaching all live Prolog terms for memory management purposes, including such terms that are being manipulated by the user's C code. Previous releases of SICStus Prolog provided direct access to Prolog terms and the ability to tell the memory manager that a given memory address points to a Prolog term, but this approach was too low level and highly error-prone. The current design is modeled after and largely compatible with Quintus Prolog release 3.

SP_term_refs are created dynamically. At any given time, an SP_term_ref has a value (a Prolog term). This value can be examined, accessed, and updated by the support functions described in this section.

It is important to understand the rules governing the scope of SP_term_refs in conjunction with calls from Prolog to C and vice versa:

A new SP_term_ref whose value is [] is created by calling:

SP_term_ref SP_new_term_ref(void)

The value of the SP_term_ref to is set to the value of the SP_term_ref from by calling SP_put_term(to,from). The previous value of to is lost:

void SP_put_term(SP_term_ref to, SP_term_ref from)

Each Prolog atom is represented internally by a unique integer, represented in C as an unsigned long. This mapping between atoms and integers depends on the execution history. Certain functions require this representation as opposed to an SP_term_ref. It can be obtained by a special argument type declaration when calling C from Prolog, by calling SP_get_atom(), or by looking up an encoded string s in the Prolog symbol table by calling SP_atom_from_string(s):

unsigned long SP_atom_from_string(char *s)

The encoded string containing the characters of a Prolog atom a can be obtained by calling:

char *SP_string_from_atom(unsigned long a)

The length of the encoded string representing a Prolog atom a can be obtained by calling:

int SP_atom_length(unsigned long a)

Same as strlen(SP_string_from_atom(a)) but runs in O(1) time.

Prolog atoms, and the space occupied by their print names, are subject to garbage collection when the number of atoms has reached a certain threshold, under the control of the agc_margin Prolog flag (see State Info), or when the atom garbage collector is called explicitly. The atom garbage collector will find all references to atoms from the Prolog specific memory areas, including SP_term_refs and arguments passed from Prolog to foreign language functions. However, atoms created by SP_atom_from_string and merely stored in a local variable are endangered by garbage collection. The following functions make it possible to protect an atom while it is in use. The operations are implemented using reference counters to cater for multiple, independent use of the same atom in different foreign resources:

int SP_register_atom(unsigned long a)

Registers the atom a with the Prolog memory manager by incrementing its reference counter. Returns a nonzero value if the operation succeeds.

int SP_unregister_atom(unsigned long a)

Unregisters the atom a with the Prolog memory manager by decrementing its reference counter. Returns a nonzero value if the operation succeeds.


Node:Creating Prolog Terms, Next:, Previous:Creating and Manipulating SP_term_refs, Up:Support

Creating Prolog Terms

These functions create a term and store it as the value of an SP_term_ref, which must exist prior to the call. They return zero if the conversion fails (as far as failure can be detected), and a nonzero value otherwise, assigning to t the converted value. Note that the term chars here refers to a list of character codes, rather than to one-char atoms:

int SP_put_variable(SP_term_ref t)
Assigns to t a new Prolog variable.
int SP_put_integer(SP_term_ref t, long l)
Assigns to t a Prolog integer from a C long integer.
int SP_put_float(SP_term_ref t, double d)
Assigns to t a Prolog float from a C double.
int SP_put_atom(SP_term_ref t, unsigned long a)
Assigns to t a Prolog atom from a, which must be the canonical representation of a Prolog atom. (see Calling C).
int SP_put_string(SP_term_ref t, char *name)
Assigns to t a Prolog atom from a encoded C string.
int SP_put_address(SP_term_ref t, void *pointer)
Assigns to t a Prolog integer from a C pointer.

The pointer must be NULL or an address having the four most significant bits consistent with the smallest non-NULL value returned by the function malloc(). In particular, under Linux, these bits must be zero. Furthermore, the address must be aligned on a four bytes boundary.

NULL is converted to the integer 0.

int SP_put_list_chars(SP_term_ref t, SP_term_ref tail, char *s)
Assigns to t a Prolog list of the character codes represented by the encoded string s, prepended to the value of tail.
int SP_put_list_n_chars(SP_term_ref t, SP_term_ref tail, long n, char *s)
Assigns to t a Prolog list of the character codes represented by the first n bytes in encoded string s, prepended in front of the value of tail.
int SP_put_number_chars(SP_term_ref t, char *s)
Assigns to t a Prolog number by parsing the string in s.
int SP_put_functor(SP_term_ref t, unsigned long name, int arity)
Assigns to t a Prolog compound term with all the arguments unbound variables. If arity is 0, assigns the Prolog atom whose canonical representation is name to t. This is similar to calling functor/3 with the first argument unbound and the second and third arguments bound to an atom and an integer, respectively.
int SP_put_list(SP_term_ref t)
Assigns to t a Prolog list whose head and tail are both unbound variables.
int SP_cons_functor(SP_term_ref t, unsigned long name, int arity, SP_term_ref arg, ...)
Assigns to t a Prolog compound term whose arguments are the values of arg... If arity is 0, assigns the Prolog atom whose canonical representation is name to t. This is similar to calling =../2 with the first argument unbound and the second argument bound.
int SP_cons_list(SP_term_ref t, SP_term_ref head, SP_term_ref tail)
Assigns to t a Prolog list whose head and tail are the values of head and tail.


Node:Accessing Prolog Terms, Next:, Previous:Creating Prolog Terms, Up:Support

Accessing Prolog Terms

These functions will take an SP_term_ref and convert it to C data. They return zero if the conversion fails, and a nonzero value otherwise, and (except the last one) store the C data in output arguments. Note that the term chars here refers to a list of character codes, rather than to one-char atoms:

int SP_get_integer(SP_term_ref t, long *l)
Assigns to *l the C long corresponding to a Prolog number. The value must fit in *l for the operation to succeed.
int SP_get_float(SP_term_ref t, double *d)
Assigns to *d the C double corresponding to a Prolog number.
int SP_get_atom(SP_term_ref t, unsigned long *a)
Assigns to *a the canonical representation of a Prolog atom.
int SP_get_string(SP_term_ref t, char **name)
Assigns to *name a pointer to the encoded string representing the name of a Prolog atom. This string must not be modified.
int SP_get_address(SP_term_ref t, void **pointer)
Assigns to *pointer a C pointer from a Prolog term. The term should be an integer whose value should be a valid second argument to SP_put_address() (see Creating Prolog Terms).
int SP_get_list_chars(SP_term_ref t, char **s)
Assigns to *s a zero-terminated array containing an encoded string which corresponds to the given Prolog list of character codes. The array is subject to reuse by other support functions, so if the value is going to be used on a more than temporary basis, it must be moved elsewhere.
int SP_get_list_n_chars(SP_term_ref t, SP_term_ref tail, long n, long *w, char *s)
Copies into s the encoded string representing the character codes in the initial elements of list t, so that at most n bytes are used. The number of bytes actually written is assigned to *w. tail is set to the remainder of the list. The array s must have room for at least n bytes.
int SP_get_number_chars(SP_term_ref t, char **s)
Assigns to *s a zero-terminated array of characters corresponding to the printed representation of a Prolog number. The array is subject to reuse by other support functions, so if the value is going to be used on a more than temporary basis, it must be moved elsewhere.
int SP_get_functor(SP_term_ref t, unsigned long *name, int *arity)
Assigns to *name and *arity the canonical representation and arity of the principal functor of a Prolog compound term. If the value of t is an atom, then that atom is assigned to *name and 0 is assigned to *arity. This is similar to calling functor/3 with the first argument bound to a compound term or an atom and the second and third arguments unbound.
int SP_get_list(SP_term_ref t, SP_term_ref head, SP_term_ref tail)
Assigns to head and tail the head and tail of a Prolog list.
int SP_get_arg(int i, SP_term_ref t, SP_term_ref arg)
Assigns to arg the i:th argument of a Prolog compound term. This is similar to calling arg/3 with the third argument unbound.


Node:Testing Prolog Terms, Next:, Previous:Accessing Prolog Terms, Up:Support

Testing Prolog Terms

There is one general function for type testing of Prolog terms and a set of specialized, more efficient, functions, one for each term type:

int SP_term_type(SP_term_ref t)
Depending on the type of the term t, one of SP_TYPE_VARIABLE, SP_TYPE_INTEGER, SP_TYPE_FLOAT, SP_TYPE_ATOM, or SP_TYPE_COMPOUND is returned.
int SP_is_variable(SP_term_ref t)
Returns nonzero if the term is a Prolog variable, zero otherwise.
int SP_is_integer(SP_term_ref t)
Returns nonzero if the term is a Prolog integer, zero otherwise.
int SP_is_float(SP_term_ref t)
Returns nonzero if the term is a Prolog float, zero otherwise.
int SP_is_atom(SP_term_ref t)
Returns nonzero if the term is a Prolog atom, zero otherwise.
int SP_is_compound(SP_term_ref t)
Returns nonzero if the term is a Prolog compound term, zero otherwise.
int SP_is_list(SP_term_ref t)
Returns nonzero if the term is a Prolog list, zero otherwise.
int SP_is_atomic(SP_term_ref t)
Returns nonzero if the term is an atomic Prolog term, zero otherwise.
int SP_is_number(SP_term_ref t)
Returns nonzero if the term is a Prolog number, zero otherwise.


Node:Unifying and Comparing Terms, Next:, Previous:Testing Prolog Terms, Up:Support

Unifying and Comparing Terms

int SP_unify(SP_term_ref x, SP_term_ref y)
Unifies two terms, returning zero on failure and nonzero on success.
int SP_compare(SP_term_ref x, SP_term_ref y)
Returns -1 if x @< y, 0 if x == y and 1 if x @> y


Node:Operating System Services, Previous:Unifying and Comparing Terms, Up:Support

Operating System Services

The usual C library memory allocation functions (malloc, realloc, and free) may not work properly in foreign code. The following functions provide these services from SICStus Prolog's memory manager:

void *SP_malloc(unsigned int size)
Returns a properly aligned pointer to a block of at least size bytes.
void *SP_realloc(void *ptr, unsigned int size)
Changes the size of the block referenced by ptr to size bytes and returns a pointer to the (possibly moved) block. The contents will be unchanged up to the lesser of the new and old sizes. The block referenced by ptr must have been obtained by a call to SP_malloc or SP_realloc, and must not have been released by a call to SP_free or SP_realloc.
void SP_free(void *ptr)
Releases the block referenced by ptr, which must have been obtained by a call to SP_malloc or SP_realloc, and must not have been released by a call to SP_free or SP_realloc.

SICStus Prolog caches the name of the current working directory. To take advantage of the cache and to keep it consistent, foreign code should call the following interface functions instead of calling chdir() and getcwd() directly:

int SP_chdir(char *path)
Cause a directory pointed to by path to become the current working directory. Returns 0 upon successful completion. Otherwise, a value of -1 is returned and errno is set to indicate the error.
char *SP_getcwd(char *buf, unsigned int size);

Returns a pointer to the current directory pathname. If buf is not NULL, the pathname will be stored in the space pointed to by buf. If buf is a NULL pointer, size bytes of space will be obtained using SP_malloc(). In this case, the pointer returned may be used as the argument in a subsequent call to SP_free(). Returns NULL with errno set if size is not large enough to store the pathname.


Node:Calling Prolog, Next:, Previous:Support, Up:Mixing C and Prolog

Calling Prolog from C

In development and runtime systems alike, Prolog and C code may call each other to arbitrary depths.

Before calling a predicate from C you must look up the predicate definition by module, name, and arity. The function SP_predicate() will return a pointer to this definition or return NULL if the predicate is not visible in the module. This definition could be used in more than one call to the same predicate. The module specification is optional. If NULL or "" (the empty string) is given then the default type-in module (see Module Spec) is assumed:

SP_pred_ref SP_predicate(char *name_string,
                         long arity,
                         char *module_string)

Note that the first and third arguments point to encoded strings, representing the characters of the predicate and module name.

The function SP_pred() may be used as an alternative to the above. The only difference is that the name and module arguments are passed as Prolog atoms rather than strings, and the module argument is mandatory. This saves the cost of looking up the two arguments in the Prolog symbol table. This cost dominates the cost of SP_predicate():

SP_pred_ref SP_pred(unsigned long name_atom,
                    long arity,
                    unsigned long module_atom)


Node:Finding One Solution of a Call, Next:, Previous:Calling Prolog, Up:Calling Prolog

Finding One Solution of a Call

The easiest way to call a predicate if you are only interested in the first solution is to call the function SP_query(). It will create a goal from the predicate definition and the arguments, call it, and commit to the first solution found, if any.

Returns SP_SUCCESS if the goal succeeded, SP_FAILURE if it failed, and SP_ERROR if an error condition occurred. Only when the return value is SP_SUCCESS are the values in the query arguments valid, and will remain so until backtracking into any enclosing query:

int SP_query(SP_pred_ref predicate, SP_term_ref arg1, ...)

If you are only interested in the side effects of a predicate you can call SP_query_cut_fail(). It will try to prove the predicate, cut away the rest of the solutions, and finally fail. This will reclaim the storage used after the call, and throw away any solution found:

int SP_query_cut_fail(SP_pred_ref predicate, SP_term_ref arg1, ...)


Node:Finding Multiple Solutions of a Call, Next:, Previous:Finding One Solution of a Call, Up:Calling Prolog

Finding Multiple Solutions of a Call

If you are interested in more than one solution a more complicated scheme is used. You find the predicate definition as above but you don't call the predicate directly.

  1. Set up a call with SP_open_query()
  2. Call SP_next_solution() to find a solution. Call this predicate again to find more solutions if there are any.
  3. Terminate the call with SP_close_query() or SP_cut_query()

The function SP_open_query() will return an identifier of type SP_qid that you use in successive calls, or NULL, if given an invalid predicate reference. Note that if a new query is opened while another is already open, the new query must be terminated before exploring the solutions of the old one. That is, queries must be strictly nested:

SP_qid SP_open_query(SP_pred_ref predicate, SP_term_ref arg1, ...)

The function SP_next_solution() will cause the Prolog engine to backtrack over any current solution of an open query and look for a new one. The given argument must be the innermost query that is still open, i.e. it must not have been terminated explicitly by SP_close_query() or SP_cut_query() or implicitly by an unsuccessful call to SP_next_solution(). Returns SP_SUCCESS for success, SP_FAILURE for failure, SP_ERROR if an error condition occurred. Only when the return value is SP_SUCCESS are the values in the query arguments valid, and will remain so until backtracking into this query or an enclosing one:

int SP_next_solution(SP_qid query)

A query must be terminated in either of two ways. The function SP_cut_query() will discard the choices created since the corresponding SP_open_query(), like the goal !. The current solution is retained in the arguments until backtracking into any enclosing query. The given argument does not have to be the innermost open query; any open queries in its scope will also be cut. Returns SP_SUCCESS for success and SP_ERROR for invalid usage:

int SP_cut_query(SP_qid query)

Alternatively, the function SP_close_query() will discard the choices created since the corresponding SP_open_query(), and then backtrack into the query, throwing away any current solution, like the goal !, fail. The given argument does not have to be the innermost open query; any open queries in its scope will also be closed. Returns SP_SUCCESS for success and SP_ERROR for invalid usage:

int SP_close_query(SP_qid query)


Node:Calling Prolog Asynchronously, Next:, Previous:Finding Multiple Solutions of a Call, Up:Calling Prolog

Calling Prolog Asynchronously

A Prolog execution may be interrupted by signals or similar asynchronous events. If you wish to call Prolog back from a signal handler you cannot use SP_query() etc. directly. The call to Prolog has to be delayed until a time when the Prolog execution can accept an interrupt. The function SP_event() serves this purpose, and installs the function func to be called from Prolog when the execution can accept a callback. Returns non-zero iff installation succeeded. func is called with arg as first argument.

A queue of functions, with corresponding arguments, is maintained; that is, if several calls to SP_event() occur before Prolog can a accept an interrupt, the functions are queued and executed in turn at the next possible opportunity. Note that the queuing facility is only safe for signal handlers installed using SP_signal() (see below).

Depending on the value returned from func, the interrupted Prolog execution will just continue (SP_SUCCESS) or backtrack (SP_FAILURE or SP_ERROR). An exception raised by func will be processed in the interrupted Prolog execution. In case of fail or exception the event queue is flushed:

int SP_event(int (*func)(), void *arg)

A signal handler having called SP_event() should call SP_continue() as its last action, to ensure that the interrupt is processed as early as possible:

void SP_continue()

To install a function, func, as a handler for the signal sig, call:

void (*SP_signal (int sig, void (*func)()))()

SP_signal() will also, if permitted by the operating system, add sig to a set of signals which are all blocked during the handling of the event queue. Some operating systems require that:

void (*SP_reinstall_signal (int sig, void (*func)()))()

be called from a signal handler to unblock or reinstall the handler. This function should be called before SP_continue().

The following piece of C code illustrates these facilities. The function signal_init() installs the function signal_handler() as the primary signal handler for the signals USR1 and USR2. That function invokes the predicate prolog_handler/1 as the actual signal handler, passing the signal number as an argument to the predicate.

SP_pred_ref event_pred;

static int signal_event(signal_no)
     void *signal_no;
{
  SP_term_ref x=SP_new_term_ref();
  int rc;

  SP_put_integer(x, (int)signal_no);
  rc = SP_query(event_pred, x);
  if (rc == SP_ERROR && SP_exception_term(x))
    SP_raise_exception(x);        /* Propagate any raised exception */
  return rc;
}

static void signal_handler(sig)
     int sig;
{
  SP_event(signal_event, (void *)sig);
  SP_reinstall_signal(sig, signal_handler);
  SP_continue();
}

void signal_init()
{
  event_pred = SP_predicate("prolog_handler",1,"");

  SP_signal(SIGUSR1, signal_handler);
  SP_signal(SIGUSR2, signal_handler);
}


Node:Exception Handling in C, Previous:Calling Prolog Asynchronously, Up:Calling Prolog

Exception Handling in C

When an exception has been raised, the functions SP_query(), SP_query_cut_fail() and SP_next_solution() return SP_ERROR. To access the exception term (the argument of the call to raise_exception/1), which is asserted when the exception is raised, the function SP_exception_term() is used. As a side effect, the exception term is retracted, so if your code wants to pass the exception term back to Prolog, it must use the SP_raise_exception() function below. If an exception term exists, SP_exception_term() retracts it and stores it as the value of an SP_term_ref which must exist prior to the call and returns nonzero. Otherwise, it returns zero:

int SP_exception_term(SP_term_ref t)

To raise an exception from a C function called from Prolog, just call SP_raise_exception(t) where t is the SP_term_ref whose value is the exception term. The glue code will detect that an exception has been raised, any value returned from the function will be ignored, and the exception will be passed back to Prolog:

void SP_raise_exception(SP_term_ref t)


Node:SICStus Streams, Next:, Previous:Calling Prolog, Up:Mixing C and Prolog

SICStus Streams

With the SICStus Prolog C interface, the user can define his/her own streams as well as from C read or write on the predefined streams. The stream interface is modeled after Quintus Prolog release 2. It provides:


Node:Prolog Streams, Next:, Previous:SICStus Streams, Up:SICStus Streams

Prolog Streams

From the Prolog level there is a unique number that identifies a stream. This identifier can be converted from/to a Prolog stream:

stream_code(+Stream,?StreamCode)
stream_code(?Stream,+StreamCode)

StreamCode is the C stream identifier (an integer) corresponding to the Prolog stream Stream. This predicate is only useful when streams are passed between Prolog and C. Note that StreamCode no longer has any relation to the file descriptor.

The StreamCode is a Prolog integer representing a SP_stream * pointer whose value should be a valid second argument to SP_put_address() (see Creating Prolog Terms).

To read or write on a Prolog stream from C, special versions of the most common standard C I/O functions are used:

int SP_getc(void)
int SP_fgetc(SP_stream *s)
void SP_putc(int c)
void SP_fputc(int c, SP_stream *s)

The above functions deliver or accept wide character codes.

void SP_puts(char *string)
void SP_fputs(char *string, SP_stream *s)
int SP_printf(char *format, ...)
int SP_fprintf(SP_stream *s, char *format, ...)
int SP_fflush(SP_stream *s)
int SP_fclose(SP_stream *s)

The above functions expect and deliver encoded strings in their char * and char ** arguments. Specifically, in the SP_printf() and SP_fprintf() functions, first the formatting operation will be performed. The resulting string will be assumed to be in internal encoding, and will be then output using the SP_puts() or SP_fputs() function (see below). This means, e.g., that the %c printf conversion specification can only be used for ASCII characters, and the strings included using a %s specification should also be ASCII strings, or already transformed to the encoded form.

The SP_puts() and SP_fputs() functions first convert their encoded string argument into a sequence of wide character codes, and then output these on the required stream according to the external encoding; see WCX Foreign Interface.

There are three predefined streams accessible from C:

SP_stdin
Standard input. Refers to the same stream as user_input in Prolog. Which stream is referenced by user_input is controlled by the flag user_input (see prolog_flag/3) .
SP_stdout
Standard output. Refers to the same stream as user_output in Prolog. Which stream is referenced by user_output is controlled by the flag user_output (see prolog_flag/3).
SP_stderr
Standard error. Refers to the same stream as user_error in Prolog. Which stream is referenced by user_error is controlled by the flag user_error (see prolog_flag/3).
SP_curin
Current input. It is initially set equal to SP_stdin. It can be changed with the predicates see/1 and set_input/1.
SP_curout
Current output. It is initially set equal to SP_stdout. It can be changed with the predicates tell/1 and set_output/1.

Note that these variables are read only. They are set but never read by the stream handling.


Node:Defining a New Stream, Next:, Previous:Prolog Streams, Up:SICStus Streams

Defining a New Stream

The following steps are required to define a new stream in C:


Node:Low Level I/O Functions, Next:, Previous:Defining a New Stream, Up:Defining a New Stream

Low Level I/O Functions

For each new stream the appropriate low level I/O functions have to be defined. Error handling, prompt handling and character counting is handled in a layer above these functions. They all operate on a user defined private data structure pointed out by user_handle in SP_stream.

User defined low level I/O functions may invoke Prolog code and use the support functions described in the other sections of this chapter.

int my_fgetc(void *handle)
Should return the character read or -1 on end of file.
int my_fputc(char c, int handle)
Should write the character c and return the character written.
int my_flush(void *handle)
Should flush the stream and return 0 on success, EOF on error.
int my_eof(void *handle)
Should return 1 on end of file, else 0.
void my_clrerr(void *handle)
Should reset the stream's error and EOF indicators.
int my_close(void *handle)
Should close the stream and return zero.


Node:Installing a New Stream, Next:, Previous:Low Level I/O Functions, Up:Defining a New Stream

Installing a New Stream

A new stream is made accessible to Prolog using one of the functions:

int SP_make_stream(
        void *handle,
        int (*sgetc)(),
        int (*sputc)(),
        int (*sflush)(),
        int (*seof)(),
        void (*sclrerr)(),
        int (*sclose)(),
        SP_stream **stream)

int SP_make_stream_context(
        void *handle,
        int (*sgetc)(),
        int (*sputc)(),
        int (*sflush)(),
        int (*seof)(),
        void (*sclrerr)(),
        int (*sclose)(),
        SP_stream **stream,
	unsigned long option,
	int context)

The functions return SP_SUCCESS on success and SP_ERROR for invalid usage, and will:

The handle pointer will be supplied as the handle argument in the calls to the low level functions.

A stream without a close function will be treated as not closable i.e. close/1 will not have any effect on it.

The SP_make_stream_context function has two additional arguments supplying information related to the handling of wide characters; see WCX Foreign Interface.


Node:The Internal Representation of a Prolog Stream, Previous:Installing a New Stream, Up:Defining a New Stream

Internal Representation

For most streams you don't have to know anything about the internal representation but there may be occasions when you have to set some fields manually or do some processing on all streams of a particular type. SICStus Prolog maintain a circular list of stream objects of type SP_stream.

SP_stream *backward;
SP_stream *forward;
Used for linking streams together. The insertion is done by SP_make_stream() and the deletion is done from the Prolog predicate close/1.
char *filename;
This field is set to the empty string, "", by SP_make_stream(). May be set to a suitable encoded string, provided the string will not be overwritten until the stream is closed.
unsigned long mode;
A bit vector that contains information about the access modes supported, if the stream is a TTY stream etc. It is not available to the user but the TTY property can be set by the function:
void SP_set_tty(SP_stream *s)

int fd;
The I/O descriptor if the stream is associated with a file, socket etc. Otherwise a negative number.
void *user_handle;
This is the pointer to the user supplied private data for the stream. In the case of SICStus Prolog predefined file streams the user_handle could be a pointer to the standard I/O FILE.

There is no standard way to tell if a stream is user defined. You have to save pointers to the streams created or check if one of the stream functions installed is user defined, i.e:

int is_my_stream(SP_stream *s)
{
  return (s->sclose == my_close);
}


Node:Hookable Standard Streams, Previous:Defining a New Stream, Up:SICStus Streams

Hookable Standard Streams

As of release 3.7, the standard I/O streams (input, output, and error) are hookable, i.e. the streams can be redefined by the user.

SP_UserStreamHook *SP_set_user_stream_hook(SP_UserStreamHook *hook)
Sets the user-stream hook to hook.
SP_UserStreamPostHook *SP_set_user_stream_post_hook(SP_UserStreamPostHook *hook)
Sets the user-stream post-hook to hook.

These hook functions must be called before SP_initialize() (see Initializing the Prolog Engine). In custom built development systems, they may be called in the hook function SU_initialize(). See The spld utility.


Node:Writing User-stream Hooks, Next:, Previous:Hookable Standard Streams, Up:Hookable Standard Streams

Writing User-stream Hooks

The user-stream hook is, if defined, called during SP_initialize(). It has the following prototype:

SP_stream *user_stream_hook(int which)

If the hook is not defined, SICStus will attempt to open the standard TTY/console versions of these streams. If they are unavailable (such as for windowed executables under Windows), the result is undefined.

It is called three times, one for each stream. The which argument indicates which stream it is called for. The value of which is one of:

SP_STREAMHOOK_STDIN
Create stream for standard input.
SP_STREAMHOOK_STDOUT
Create stream for standard output.
SP_STREAMHOOK_STDERR
Create stream for standard error.

The hook should return a standard SICStus I/O stream, as described in Defining a New Stream.


Node:Writing User-stream Post-hooks, Next:, Previous:Writing User-stream Hooks, Up:Hookable Standard Streams

Writing User-stream Post-hooks

The user-stream post-hook is, if defined, called after all the streams have been defined, once for each of the three standard streams. It has a slightly different prototype:

void user_stream_post_hook(int which, SP_stream *str)

where str is a pointer to the corresponding SP_stream structure. There are no requirements as to what this hook must do; the default behavior is to do nothing at all.

The post-hook is intended to be used to do things which may require that all streams have been created.


Node:User-stream Hook Example, Previous:Writing User-stream Post-hooks, Up:Hookable Standard Streams

User-stream Hook Example

This section contains an example of how to create and install a set of user-streams.

The hook is set by calling SP_set_user_stream_hook() in the main program like this:

SP_set_user_stream_hook((SP_UserStreamHook *)user_strhook);

Remember: SP_set_user_stream_hook() and SP_set_user_stream_post_hook() must be called before SP_initialize().

The hook user_strhook() is defined like this:

SP_stream *user_strhook(int std_fd)
{
  SP_stream *s;

  SP_make_stream(NULL, my_getc, my_putc, my_flush, my_eof, my_clrerr, NULL, &s);

  return s;
}

See Installing a New Stream for a description on the parameters to SP_make_stream().


Node:Hooks, Next:, Previous:SICStus Streams, Up:Mixing C and Prolog

Hooks

The user may define functions to be called at certain occasions by the Prolog system. This is accomplished by passing the functions as arguments to the following set-hook-functions. The functions can be removed by passing a NULL.

typedef int (SP_ReadHookProc) (int fd)
SP_ReadHookProc SP_set_read_hook (SP_ReadHookProc *)
The installed function is called before reading a character from fd provided it is associated with a terminal device. This function shall return nonzero when there is input available at fd. It is called repeatedly until it returns nonzero.
typedef void (SP_VoidFun) (void)
SP_VoidFun * SP_set_reinit_hook (SP_VoidFun *)
The installed function is called upon abort and reinitialization. The call is made after SICStus Prolog's signal handler installation but before any initializations are run and the version banners are displayed. Calling Prolog from functions invoked through this hook is not supported. (This hook is not available in runtime systems.)
typedef void (SP_VoidFun) (void);
SP_VoidFun * SP_set_interrupt_hook (SP_VoidFun *)
The installed function is called on occasions like expansion of stacks, garbage collection and printouts, in order to yield control to special consoles etc. for interrupt checking. Calling Prolog from functions invoked through this hook is not supported. (This hook is not available in runtime systems.)


Node:Stand-alone Executables, Next:, Previous:Hooks, Up:Mixing C and Prolog

Stand-alone Executables

So far we have only discussed foreign code as pieces of code loaded into a Prolog executable. This is often not the desired situation. Instead, people often want to create stand-alone executables. i.e. an application where Prolog is used as a component, accessed through the API described in the previous sections.


Node:Runtime Systems, Next:, Previous:Stand-alone Executables, Up:Stand-alone Executables

Runtime Systems

Stand-alone applications containing debugged Prolog code and destined for end-users are typically packaged as runtime systems. No SICStus license is needed by a runtime system. A runtime system has the following limitations:


Node:Runtime Systems on Target Machines, Next:, Previous:Runtime Systems, Up:Stand-alone Executables

Runtime Systems on Target Machines

When a runtime system is delivered to the end user, chances are that the user does not have an existing SICStus installation. To deliver such an executable, you need:

the executable
This is your executable program, usually created by spld (see The spld utility).
the runtime kernel
This is a shared object or a DLL, usually $SP_PATH/../libsprt38.so under UNIX, or %SP_PATH%\..\sprt38.dll under Windows.
the runtime library
The saved state $SP_PATH/bin/sprt.sav contains the built-in predicates written in Prolog. It is restored into the program at runtime by the function SP_initialize().
your Prolog code
As a saved state, .po files, .ql, or source code (.pl files). They must be explicitly loaded by the program at runtime (see Loading Prolog Code).
your linked foreign resources
Any linked foreign resources which are not pre-linked with the executable, including any linked foreign resources for library modules which are located in $SP_PATH/library.

See Launching Runtime Systems on Target Machines, for more information about runtime systems on Target Machines.


Node:The spld utility, Next:, Previous:Runtime Systems on Target Machines, Up:Stand-alone Executables

The spld utility

A stand-alone executable is created using the spld utility. This utility replaces the scripts spmkrs and spmkds in previous versions of SICStus. It is invoked as:

% spld [ Option | InputFile ] ...

spld takes the files specified on the command line and combines them into an executable file, much like the UNIX ld or the Windows link.

The input to spld can be divided into Options and Files and they can be arbitrarily mixed on the command line. Anything not interpreted as an option will be interpreted as an input file. The following options are available:

--help
Prints out a summary of all options.
-v
--verbose
Print detailed information about each step in the compilation/linking sequence.
--version
Prints out the version number of spld.
-o
--output
Specify output filename. The default depends on the linker (i.e. "a.out" on UNIX systems).
-D
--development
Create a development system (with debugger, compiler, etc.). The default is to create a runtime system.
--main=type
Specify what to do when running the executable, or, in other words, what kind of user_main() program to use. The possible values are prolog, restore, load and user.

prolog
Implies -D. The executable will start the Prolog toplevel interpreter. This is the default if -D is specified and no .sav, .pl, .po, or .ql files are specified.
user
The user supplies his/her own main-program by including C-code (object file or source) which defines a function user_main().
int user_main(int argc, char *argv[])
user_main() is responsible for initializing the Prolog engine, loading code, and starting any Prolog-queries. This option is not compatible with -D.
restore
The executable will restore a saved-state. This is the default if a .sav file is found among Files. It is only meaningful to specify one .sav file. The saved-state should be created using save_program/2, otherwise the executable will simply restore the state and then terminate. Not compatible with -D.
load
The executable will load any Prolog code specified on the command line, i.e. files with extension .pl, .po or .ql. It will then try to prove the goal runtime_entry(start). This is the default if there are .pl, .po or .ql but no .sav files among Files. Not compatible with -D.

--window
Win32 only. Create a windowed executable. A console window will be opened and connected to the Prolog standard streams. If --main=user is specified, user_main() should not set the user-stream hooks. C/C++ source code files specified on the command-line will be compiled with -DSP_WIN=1 if this option is given.
--moveable
Under UNIX, paths are normally hardcoded into executables in order for them to find the SICStus libraries and bootfiles. Two paths are normally hardcoded; the value of SP_PATH and, where possible, the runtime library search path using the -R linker option (or equivalent). If the linker does not support the -R flag (or an equivalent), a wrapper script is generated instead which sets LD_LIBRARY_PATH (or equivalent).

The --moveable option turns of this behavior, so the executable is not dependent on SICStus being installed in a specific place. If this flag is given, the executable will rely on environment variables (SP_PATH (see Environment Variables) and LD_LIBRARY_PATH, etc.) to find all relevant files.

Under Windows, this option is always on, since Windows applications do no need to hardcode paths in order for them to find out where they're installed. See Launching Runtime Systems on Target Machines, for more information on how SICStus locates its libraries and bootfiles.

-S
--static
Prefer static linking over dynamic. When --static is specified, spld will try to use static (not shared) versions of libraries and object-files. This option can be used to minimize runtime dependencies on shared libraries/object-files.

Under UNIX, even if there is a static version of a library (such as for example Tcl/Tk (libtcl8.0.a), spld may still use the dynamic version (libtcl8.0.so). This is because there is no portable way of telling the linker to prefer static libraries over shared, it is usually only possible to link statically or dynamically; the modes are usually exclusive. In this case, spld will go with the linker's default, which is usually dynamic. If you are in a situation where you would want spld to use a static library instead of a dynamic one, you will have to hack into spld's configuration file spld.config (normally located in <installdir>/bin). We recommend that you make a copy of spld.config and specify the new configuration file using the --config=<file>. A typical modification of spld.config for this purpose may look like:

[...]
TCLLIB=-Bstatic -L/usr/local/lib -ltk8.0 -ltcl8.0 -Bdynamic
[...]
Use the new spld.config by typing
% spld [...] -S --config=/home/joe/hacked_spld.config [...]
Note: these remarks are not applicable to Win32.
--resources=ResourceList
ResourceList is a comma-separated list of resource names, describing which resources should be pre-linked with the executable. Names can be either simple resource names, for example tcltk, or they can be complete paths to a foreign resource (with or without extensions). Example
% spld [...] --resources=tcltk,clpfd,/home/joe/foobar.so
This will cause library(tcltk), library(clpfd), and /home/joe/foobar.so to be pre-linked with the executable. See also the --respath below. Not supported under Windows.
--respath=Path
Specify additional paths used for searching for resources. Path is a colon-separated list of search-paths. spld will always search the default library directory as a last resort, so if this option is not specified, only the default resources will be found. See also the --resources option above.
--config=ConfigFile
Specify another configuration file. This option is not intended for normal use.
--cflag=CFlag
CFlag is a comma-separated list of options to send to the C-compiler. Any commas in the list will be replaced by spaces.
-LD
Do not process the rest of the command-line, but send it directly to the compiler/linker. Syntactic sugar for --cflag.
--sicstus=Executable
spld relies on using SICStus during some stages of its execution. The default is the SICStus-executable installed with the distribution. Executable can be used to override this, in case the user wants to use another SICStus executable.
--interactive
-i
Only applicable with --main=load or --main=restore. Calls SP_force_interactive() (see Initializing the Prolog Engine) before initializing SICStus.
--userhook
This option enables you to define your own version of the SU_initialize() function. SU_initialize() is called by the main program before SP_initialize(). Its purpose is to call interface functions which must be called before SP_initialize(), such as SP_set_memalloc_hooks(). It is not meaningful to specify this option if --main=user is given.

SU_initialize() should be defined as:

int SU_initialize(int argc, char *argv[])
The contents of argv should not be modified. SU_initialize() should return 0 for success and non-zero for failure. If a non-zero value is returned, the development system exits with the return value as error code.

Arguments to spld which are not recognized as options are assumed to be input-files and are handled as follows:

*.pl
*.po
*.ql
These are interpreted as Prolog code and will be loaded by SP_load().
*.so
*.sl
*.s.o
*.o
*.obj
*.dll
*.lib
These files are assumed to be input-files to the linker and will be passed on unmodified.
*.c
*.cc
*.C
*.cpp
*.c++
These files are assumed to be C/C++ source code and will be compiled by the C/C++-compiler before being passed to the linker.

If an argument is still not recognized, it will be passed unmodified to the linker.


Node:spld examples, Previous:The spld utility, Up:The spld utility

Examples

  1. The character-based SICStus development system executable (sicstus) can be created using
    % spld --main=prolog -o sicstus
    

    This will create a development system which is dynamically linked and has no pre-linked foreign resources.

  2. % spld --static -D --resources=random -o main -ltk8.0 -ltcl8.0
    

    This will create a statically linked executable called main which has the resource random pre-linked (statically). The linker will receive -ltk8.0 -ltcl8.0 which will work under UNIX (if Tcl/Tk is installed correctly) but will probably fail under Windows.

  3. The follow is a little more advanced example demonstrating two things. One is how to use the --userhook option to perform initializations in development systems before SP_initialize() is called. It also demonstrates how to use this mechanism to redefine the memory manager bottom layer.
    /* --------------------------------------------------------------
     * userhook.c - an example of how to use SU_initialize() to
     *              define your own memory manager bottom layer.
     *
     * The following commands create a sicstus-executable 'msicstus'
     * which uses malloc() as its own memory manager bottom layer.
     * This is more or less equivalent to specifying "-m" to the
     * regular 'sicstus' executable, except that these memory hooks
     * print out messages when they are called.
     * --------------------------------------------------------------
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <sicstus/sicstus.h>
    
    /* for mallopt() */
    #ifdef linux
    #include <malloc.h>
    #endif
    
    void *
    my_alloc_hook (unsigned int size,
                   unsigned int align,
                   unsigned int *actual_size)
    {
      void *mem;
    
      printf ("Inside my_alloc_hook(%d,%d,%p) -> ",
              size, align, actual_size);
    
      if (align > sizeof (double))
          size += align;
    
      mem = malloc (size);
      *actual_size = size;
      if (mem)
        printf ("%p\n", mem);
      else
        printf ("NULL (malloc failed to allocate memory)\n");
    
      return mem;
    }
    
    void *
    my_init_alloc_hook (unsigned int size,
                        unsigned int align,
                        unsigned int *actual_size)
    {
      printf ("Inside my_init_alloc_hook(%d,%d,%p)\n",
              size, align, actual_size);
    
      /* Do not use MMAP on Linux. */
    #ifdef linux
      mallopt (M_MMAP_MAX, 0);
    #endif
    
      return my_alloc_hook (size, align, actual_size);
    }
    
    void *
    my_realloc_hook (void *ptr,
                     unsigned int oldsize,
                     unsigned int newsize,
                     unsigned int align,
                     unsigned int *actual_size)
    {
      void *mem;
    
      printf ("Inside my_realloc_hook(%p,%d,%d,%d,%p) -> ",
              ptr, oldsize, newsize, align, actual_size);
    
      if (align > sizeof (double))
          newsize += align;
    
      mem = realloc (ptr, newsize);
      *actual_size = newsize;
      if (mem)
        printf ("%p\n", mem);
      else
        printf ("NULL (realloc() failed to re-allocate memory)\n");
    
      return mem;
    }
    
    int
    my_free_hook (void *ptr, unsigned int size)
    {
      printf ("Inside my_free_hook(%p,%d)\n", ptr, size);
    
      free (ptr);
      return 1;
    }
    
    /* Entry point for initializations to be done before SP_initialize() */
    int
    SU_initialize (int argc, char **argv)
    {
      SP_set_memalloc_hooks (MM_USE_OTHER,
                             my_init_alloc_hook,
                             my_alloc_hook,
                             my_realloc_hook,
                             my_free_hook);
      return 0;
    }
    

    Compile userhook.c like this:

    % spld -D --userhook userhook.c -o ./msicstus
    Created "./msicstus"
    % ./msicstus
    Inside my_init_alloc_hook(524304,8,0xbfffc318)
    Inside my_alloc_hook(524304,8,0xbfffc318) -> 0x804b920
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x80cba38
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x80dba40
    Inside my_alloc_hook(65536,8,0xbfff00d0) -> 0x80eba48
    Inside my_alloc_hook(65544,8,0xbfff0110) -> 0x80fba50
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x810ba60
    Inside my_alloc_hook(65536,8,0xbfff00f4) -> 0x811ba68
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x812ba70
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x813ba78
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x814ba80
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x815ba88
    Inside my_alloc_hook(65536,8,0xbfff019c) -> 0x816ba90
    SICStus 3.8b1 (x86-linux-glibc2.1): Fri Oct 29 11:24:24 CEST 1999
    Licensed to SICS
    Inside my_free_hook(0x80fba50,65544)
    | ?-
    


Node:Instead of a Top-level Interpreter, Previous:The spld utility, Up:Stand-alone Executables

Instead of a Top-level Interpreter

Stand-alone executables may or may not have a top-level interpreter. This is in general controlled by the --main to spld (see The spld utility). When a stand-alone executable does not have a top-level interpreter, the Prolog engine must be explicitly initialized by the user and the Prolog code must be explicitly loaded.


Node:Initializing the Prolog Engine, Next:, Previous:Instead of a Top-level Interpreter, Up:Instead of a Top-level Interpreter

Initializing the Prolog Engine

The Prolog Engine is initialized by calling SP_initialize(). This must be done before any interface functions are called, except SP_force_interactive, SP_set_memalloc_hooks, SP_set_wcx_hooks, SP_set_user_stream_post_hook and SP_set_user_stream_hook. The function will allocate data areas used by Prolog, initialize command line arguments so that they can be accessed by the argv Prolog flag, and load the Runtime Library. It is called like this:

int SP_initialize(int argc, char **argv, char *boot_path)

boot_path should be the name of a directory, equivalent to $SP_PATH/bin. If boot_path is NULL, SP_initialize() will look up the value of the environment variable SP_PATH and look for the file $SP_PATH/bin/sprt.sav which contains the Runtime Library.

It returns SP_SUCCESS if initialization was successful, and SP_ERROR otherwise. If initialization was successful, further calls to SP_initialize() will be no-ops (and return SP_SUCCESS).

To unload the SICStus emulator, SP_deinitalize() can be called.

void SP_deinitialize(void)

SP_deinitialize() will make a best effort to restore the system to the state it was in at the time of calling SP_initialize(). This involves unloading foreign resources, shutting down the emulator by calling halt/0, and deallocate memory used by Prolog. SP_deinitialize() is idempotent as well, i.e. it is a no-op unless SICStus has actually been initialized.

You may also call SP_force_interactive() before calling SP_initialize(). This will force the I/O built-in predicates to treat the standard input stream as a terminal, even if it does not appear to be a terminal. Same as the -i option in development systems. (see Start).

void SP_force_interactive(void)

You may also call SP_set_memalloc_hooks() before calling SP_initialize(). This will define the bottom layer of Prolog's memory manager, in case your application has special requirements.

typedef void *(SP_AllocHook)(unsigned int size,
                             unsigned int align,
                             unsigned int *actual_sizep);
typedef void *(SP_ReAllocHook)(void *ptr,
                               unsigned int oldsize,
                               unsigned int newsize,
                               unsigned int align,
                               unsigned int *actual_sizep);
typedef int (SP_FreeHook)(void *ptr,
                          unsigned int size);

void SP_set_memalloc_hooks(int usage,
                           SP_AllocHook *init_alloc_hook,
                           SP_AllocHook *alloc_hook,
                           SP_ReAllocHook *realloc_hook,
                           SP_FreeHook *free_hook)

The effect of SP_set_memalloc_hooks is controlled by the value of usage, which should be one of:

MM_USE_MALLOC
The bottom layer will be based on malloc()/free(). The other arguments are ignored. Same as the -m option in development systems. (see Start).
MM_USE_SBRK
The bottom layer will be based on sbrk(). The default for UNIX; not available for Windows. The other arguments are ignored.
MM_USE_SPARSE
The bottom layer will be based on VirtualAlloc()/VirtualFree(). The default for Windows; not available for UNIX. The other arguments are ignored.
MM_USE_OTHER
The bottom layer will be based on the other arguments. Their meaning is explained below. See The spld utility, for an example.

In the latter case, the other arguments should be functions as specified below. Pointer arguments and values should be valid second arguments to SP_put_address() (see Creating Prolog Terms).

alloc_hook
must allocate and return a pointer to a piece of memory that has at least size bytes aligned at align in it. align is guaranteed to be a power of 2. The actual size of the piece of memory should be returned in *actual_sizep. Should return NULL if it cannot allocate any more memory.
init_alloc_hook
is a special case of alloc_hook. It will be called initially whereas alloc_hook will be called subsequently. It can do whatever initialization that this layer of memory management wants to do.
realloc_hook
is called with a piece of memory to be resized and possibly moved. ptr is the pointer, oldsize its current size. The function must allocate and return a pointer to a piece of memory that has at least newsize bytes aligned at align in it, and that has the same contents as the old block up to the lesser of oldsize and newsize. align is guaranteed to be a power of 2. The actual size of the piece of memory should be returned in *actual_sizep. Should return NULL if it cannot allocate any more memory, or if it cannot reclaim the old block in a meaningful way. In that case, Prolog will use the other functions.
free_hook
is called with a pointer to the piece of memory to be freed and its size. Should return non-zero iff the function was able to free this piece of memory. Otherwise, Prolog will keep using the memory as if it were not freed.

The default bottom layers look at the environment variables PROLOGINITSIZE, PROLOGINCSIZE, PROLOGKEEPSIZE and PROLOGMAXSIZE. They are useful to customize the default memory manager. If users redefine the bottom layer, they can choose to ignore these environment variables. See Environment Variables.


Node:Loading Prolog Code, Previous:Initializing the Prolog Engine, Up:Instead of a Top-level Interpreter

Loading Prolog Code

You can load your Prolog code with the call SP_load(). This is the C equivalent of the Prolog predicate load_files/1:

int SP_load(char *filename)

Alternatively, you can restore a saved state with the call SP_restore(), which is the C equivalent of the Prolog predicate restore/1:

int SP_restore(char *filename)

SP_load() and SP_restore() return SP_SUCCESS for success or SP_ERROR if an error condition occurred. The filename arguments in both functions are encoded strings.

Prolog error handling is mostly done by raising and catching exceptions. However, some faults are of a nature such that when they occur, the internal program state may be corrupted, and it is not safe to merely raise an exception. Memory allocation failures are examples of faults. In runtime systems, the following C macro provides an environment for handling faults:

int SP_on_fault(Stmt, Message, Cleanup)

which should occur in the scope of a char *Message declaration. Stmt is run, and if a fault occurs, Stmt is aborted, Message gets assigned a value explaining the fault, the Prolog internal state is cleaned, all queries and SP_term_refs become invalid, and Cleanup run. If Stmt terminates normally, Message is left unchanged. For example, a "fault-proof" runtime system could have the structure:

int main(int argc, char **argv)
{
  char *message;

  SP_initialize(argc, argv, "/usr/local/lib/sicstus38/bin");
loop:
  SP_on_fault(main_loop(), message,
              {printf("ERROR: %s\n",message); goto loop;});
  exit(0);
}

main_loop()
{...}

Faults that occur outside the scope of SP_on_fault() cause the runtime system to halt with an error message.

The following function can be used to raise a fault. For example, it can be used in a signal handler for SIGSEGV to prevent the program from dumping core in the event of a segmentation violation (runtime systems have no predefined signal handling):

void SP_raise_fault(char *message)


Node:Mixing Examples, Previous:Stand-alone Executables, Up:Mixing C and Prolog

Examples


Node:Train, Next:, Previous:Mixing Examples, Up:Mixing Examples

Train Example (connections)

This is an example of how to create a runtime system. The Prolog program train.pl will display a route from one train station to another. The C program train.c calls the Prolog code and writes out all the routes found between two stations:

% train.pl

connected(From, From, [From], _):- !.
connected(From, To, [From| Way], Been):-
        (   no_stop(From, Through)
        ;
            no_stop(Through, From)
        ),
        not_been_before(Been, Through),
        connected(Through, To, Way, Been).

no_stop('Stockholm', 'Katrineholm').
no_stop('Stockholm', 'Vasteras').
no_stop('Katrineholm', 'Hallsberg').
no_stop('Katrineholm', 'Linkoping').
no_stop('Hallsberg', 'Kumla').
no_stop('Hallsberg', 'Goteborg').
no_stop('Orebro', 'Vasteras').
no_stop('Orebro', 'Kumla').

not_been_before(Way, _) :- var(Way),!.
not_been_before([Been| Way], Am) :-
        Been \== Am,
        not_been_before(Way, Am).
/* train.c */

#include <stdio.h>
#include <sicstus/sicstus.h>

void write_path(SP_term_ref path)
{
  char *text = NULL;
  SP_term_ref
    tail = SP_new_term_ref(),
    via = SP_new_term_ref();

  SP_put_term(tail,path);

  while (SP_get_list(tail,via,tail))
  {
    if (text)
      printf(" -> ");

    SP_get_string(via, &text);
    printf("%s",text);
  }
  printf("\n");
}

int user_main(int argc, char **argv)
{
  int rval;
  SP_pred_ref pred;
  SP_qid goal;
  SP_term_ref from, to, path;

  /* Initialize Prolog engine. This call looks up SP_PATH in order to
   * find the Runtime Library.  */
  if (SP_FAILURE == SP_initialize(argc, argv, NULL))
    {
      fprintf(stderr, "SP_initialize failed: %s\n", SP_error_message(SP_errno));
      exit(1);
    }

  rval = SP_restore("train.sav");

  if (rval == SP_ERROR || rval == SP_FAILURE)
    {
      fprintf(stderr, "Could not restore \"train.sav\".\n");
      exit(1);
    }

  /* Look up connected/3. */
  if (!(pred = SP_predicate("connected",4,"")))
    {
      fprintf(stderr, "Could not find connected/4.\n");
      exit(1);
    }

  /* Create the three arguments to connected/4. */
  SP_put_string(from = SP_new_term_ref(), "Stockholm");
  SP_put_string(to = SP_new_term_ref(), "Orebro");
  SP_put_variable(path = SP_new_term_ref());

  /* Open the query. In a development system, the query would look like:
   *
   * | ?- connected('Stockholm','Orebro',X).
   */
  if (!(goal = SP_open_query(pred,from,to,path,path)))
    {
      fprintf(stderr, "Failed to open query.\n");
      exit(1);
    }

  /*
   * Loop through all the solutions.
   */
  while (SP_next_solution(goal))
    {
      printf("Path: ");
      write_path(path);
    }

  SP_close_query(goal);

  exit(0);
}

Create the saved-state containing the Prolog code:

% sicstus
SICStus 3.8 (sparc-solaris-5.5.1): Thu Sep 30 15:20:42 MET DST 1999
Licensed to SICS
| ?- compile(train),save_program('train.sav').
{compiling [...]/train.pl...}
{compiled [...]/train.pl in module user, 10 msec 2848 bytes}
{[...]/train.sav created in 0 msec}

yes
| ?- halt.

Create the executable using spld:

% spld --main=user train.c -o train.exe

And finally, run the executable:

% ./train
Path: Stockholm -> Katrineholm -> Hallsberg -> Kumla -> Orebro
Path: Stockholm -> Vasteras -> Orebro


Node:I/O on Lists of Character Codes, Next:, Previous:Train, Up:Mixing Examples

I/O on Lists of Character Codes

This example is taken from the SICStus Prolog library (simplified, but operational). A stream for writing is opened where the written characters are placed in a buffer. When the stream is closed a list of character codes is made from the contents of the buffer. The example illustrates the use of user definable streams.

The open_buf_stream() function opens a stream where the characters are put in a buffer. The stream is closed by stream_to_chars() which returns the list constructed on the heap.

The Prolog code (simplified):

foreign(open_buf_stream, '$open_buf_stream'(-address('SP_stream'))).
foreign(stream_to_chars, '$stream_to_chars'(+address('SP_stream'),
                                            -term)).

foreign_resource(example, [open_buf_stream,stream_to_chars]).

:- load_foreign_resource(example).

%% with_output_to_chars(+Goal, -Chars)
%% runs Goal with current_output set to a list of characters

with_output_to_chars(Goal, Chars) :-
        '$open_buf_stream'(StreamCode),
        stream_code(Stream, StreamCode),
        current_output(CurrOut),
        set_output(Stream),
        call_and_reset(Goal, Stream, CurrOut, StreamCode, Chars).

call_and_reset(Goal, Stream, CurrOut, StreamCode, Chars) :-
        call(Goal), !,
        put(0),
        '$stream_to_chars'(StreamCode, Chars),
        reset_stream(Stream, CurrOut).
call_and_reset(_, Stream, CurrOut, _, _) :-
        reset_stream(Stream, CurrOut).

reset_stream(Stream, CurrOut) :-
        set_output(CurrOut),
        close(Stream).

The C code:

#include <sicstus/sicstus.h>

struct open_chars {
  char *chars;       /* character buffer */
  int index;         /* current insertion point */
  int size;
};

#define INIT_BUFSIZE 512

static int lputc(c, buf)
     int c;
     struct open_chars *buf;
{
  if (buf->index == buf->size)  /* grow buffer if necessary */
    {
      buf->size *= 2;
      buf->chars = (char *)realloc(buf->chars, buf->size);
    }
  return (buf->chars[buf->index++] = c);
}

static int lwclose(buf)
     struct open_chars *buf;
{
  free(buf->chars);
  free(buf);
  return 0;
}

void open_buf_stream(streamp)
     SP_stream **streamp;
{
  struct open_chars *buf;

  /* Allocate buffer, create stream & return stream code */

  buf = (struct open_chars *)malloc(sizeof(struct open_chars));
  SP_make_stream(buf, NULL, lputc, NULL, NULL, NULL, lwclose,
                 streamp);

  buf->chars = (char *)malloc(INIT_BUFSIZE);
  buf->size = INIT_BUFSIZE;
  buf->index = 0;
}

void stream_to_chars(streamp, head)
     SP_stream *streamp;
     SP_term_ref head;
{
  SP_term_ref tail = SP_new_term_ref();
  struct open_chars *buf = (struct open_chars *)streamp->user_handle;

  /* Make a list of character codes out of the buffer */

  SP_put_string(tail, "[]");
  SP_put_list_chars(head, tail, buf->chars);
}


Node:Exceptions from C, Next:, Previous:I/O on Lists of Character Codes, Up:Mixing Examples

Exceptions from C

Consider, for example, a function which returns the square root of its argument after checking that the argument is valid. If the argument is invalid, the function should raise an exception instead.

/* math.c */

#include <math.h>
#include <stdio.h>
#include <sicstus/sicstus.h>

double sqrt_check(d)
     double d;
{
  if (d < 0.0)
    {    /* build a domain_error/4 exception term */
      SP_term_ref culprit=SP_new_term_ref();
      SP_term_ref argno=SP_new_term_ref();
      SP_term_ref expdomain=SP_new_term_ref();
      SP_term_ref t1=SP_new_term_ref();

      SP_put_float(culprit, d);
      SP_put_integer(argno, 1);
      SP_put_string(expdomain, ">=0.0");
      SP_cons_functor(t1, SP_atom_from_string("sqrt"), 1, culprit);
      SP_cons_functor(t1, SP_atom_from_string("domain_error"), 4,
                      t1, argno, expdomain, culprit);
      SP_raise_exception(t1);    /* raise the exception */
      return 0.0;
    }
  return sqrt(d);
}

The Prolog interface to this function is defined in a file math.pl. The function uses the sqrt() library function, and so the math library -lm has to be included:

/* math.pl */

foreign_resource(math, [sqrt_check]).

foreign(sqrt_check, c, sqrt(+float, [-float])).

:- load_foreign_resource(math).

A linked foreign resource is created:

% splfr math math.pl +c math.c +l -lm

A simple session using this function could be:

% sicstus
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
| ?- [math].
{consulting /home/san/pl/math.pl...}
{/home/san/pl/math.pl consulted, 10 msec 816 bytes}

yes
| ?- sqrt(5.0,X).

X = 2.23606797749979 ?

yes
| ?- sqrt(a,X).
{TYPE ERROR: sqrt(a,_30) - arg 1: expected number, found a}
| ?- sqrt(-5,X).
{DOMAIN ERROR: sqrt(-5.0) - arg 1: expected '>=0.0', found -5.0}

The above example used the foreign language interface with dynamic linking. To statically link math.o with the Prolog emulator, the following steps would have been taken:

% splfr math math.pl +static +c math.c +l -lm
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
{/tmp/00249aaa.c generated, 10 msec}

yes
% spmkds mathsp math
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
{/tmp/00274aaa.c generated, 0 msec}

yes
% sicstus -base ./mathsp
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
| ?- [math].
{consulting /home/san/pl/math.pl...}
{/home/san/pl/math.pl consulted, 0 msec 864 bytes}

yes
| ?- sqrt(5.0,X).

X = 2.23606797749979 ?

yes


Node:Stream Example, Previous:Exceptions from C, Up:Mixing Examples

Stream Example

This is a small example how to initialize a bidirectional socket stream (error handling omitted):

typedef struct {
  int fd;                       /* socket number */
  FILE *r_stream;               /* For reading */
  FILE *w_stream;               /* For writing */
} SocketData;

int socket_sgetc(SocketData *socket)
{
  return fgetc(socket->r_stream);
}

int socket_sputc(char c, SocketData *socket)
{
  return fputc(c, socket->w_stream);
}

int socket_sflush(SocketData *socket)
{
  return fflush(socket->w_stream);
}

int socket_seof(SocketData *socket)
{
  return feof(socket->r_stream);
}

void socket_sclrerr(SocketData *socket)
{
  clearerr(socket->r_stream);
  clearerr(socket->w_stream);
}

int socket_sclose(SocketData *socket)
{
  fclose(socket->r_stream);
  fclose(socket->w_stream);
  close(socket->fd);
  free(socket);
  return 0;
}

SP_stream *new_socket_stream(int fd)
{
  SP_stream *stream;
  SocketData *socket;

/* Allocate and initialize data local to socket */

  socket = (SocketData *)malloc(sizeof(SocketData));
  socket->fd = fd;
  socket->r_stream = fdopen(fd,"r");
  socket->w_stream = fdopen(fd,"w");

/* Allocate and initialize Prolog stream */

  SP_make_stream(
                 socket,
                 socket_sgetc,
                 socket_sputc,
                 socket_sflush,
                 socket_seof,
                 socket_sclrerr,
                 socket_sclose,
                 &stream);

/* Allocate and copy string */

  stream->filename = "socket";
  stream->fd = fd;

  return stream;
}


Node:Mixing Java and Prolog, Next:, Previous:Mixing C and Prolog, Up:Top

Mixing Java and Prolog

Jasper is a bi-directional interface between Java and SICStus. The Java-side of the interface constists of a Java package (se.sics.jasper) containing classes representing the SICStus emulator (SICStus, SPTerm, etc). The Prolog part is designed as library module (library(jasper)) and an extension to the foreign language interface.

The foreign language interface extensions enables Java-methods to be called as Prolog predicates using foreign/3 declarations, much like the C-Prolog facilities described in Mixing C and Prolog.

The library module library(jasper) (see Jasper) provides functionality for controlling the loading and unloading the JVM, meta-call functionality (jasper_call_instance/6, jasper_call_static/6), and predicates for managing global and local references. These are provided in order to make it easy to call Java methods on-the-fly from Prolog without having to create a foreign resource first.

Jasper can be used in two modes, depending on which system acts as Parent Application. If Java is the parent application, the SICStus runtime kernel will be loaded into the JVM using the System.loadLibrary() method (this is done indirectly when instantiating the SICStus object). In this mode, SICStus is loaded as a runtime system (see Runtime Systems).

If SICStus is the parent application, Java will be loaded as a foreign resource using the query use_module(library(jasper)). The Java engine is initialized using jasper_initialize/[1-2].


Node:Getting Started, Next:, Previous:Mixing Java and Prolog, Up:Mixing Java and Prolog

Getting Started

See Getting Started, for a detailed description of how to get started using the interface. It addresses issues such as finding SICStus from within Java and vice versa, setting the classpath correctly, etc. If you have trouble in getting started with Jasper, read that chapter before contacting SICStus Support.


Node:Calling Java from Prolog, Next:, Previous:Getting Started, Up:Mixing Java and Prolog

Calling Java from Prolog

Java methods can be called from Prolog in two ways. One way is to use the meta-call predicates provided in library(jasper). See Jasper for more information. Another, more efficient, method will be described here.

Java methods can be called much in the same way as C functions are called (see Calling C); by creating a foreign resource. When loaded, this resource installs a set of predicates which are mapped onto Java-methods such that invoking a Java method looks like any other Prolog predicate call. Such methods are sometimes called direct mapped.

In fact, a foreign resource (as defined in Foreign Resources) is not language specific itself. The language is instead specified in the second argument to the foreign/3 fact and it is possible to mix foreign C functions with foreign Java methods.

How a foreign resource is created in general is described in detail in Creating the Linked Foreign Resource. The following section(s) will focus on the Java-specific parts of foreign resources.


Node:Static and Dynamic Linking for Jasper, Next:, Previous:Calling Java from Prolog, Up:Calling Java from Prolog

Static and Dynamic Linking

There is only limited support for static foreign resources (see Foreign Resources) (mainly due to the fact the Java does not support statically linked code). Even though Jasper allows static foreign resources may be used to some extent, it is recommended that only dynamic foreign resources are used.


Node:Declaring Java-methods, Previous:Static and Dynamic Linking for Jasper, Up:Calling Java from Prolog

Declarating Java-methods

Java-methods are declared similarly to C-functions. There are two major differences. The first is how methods are identified. It is not enough to simply use an atom as the C interface does. Instead, a term method/3 is used:

method(+ClassName,+MethodName,+Flags)
Used as first argument to foreign/3 when declaring Java methods. The first argument is an atom containing the Fully Qualified Classname of the class (for example, java/lang/String) The second argument is the method name. The third argument is a list of flags. Possible flags are instance or static, indicating whether or not the method is static or non-static. Non-static methods must have an object-reference as their first argument. This is a reference to the object on which the method will be invoked.

This term is then used to identify the method in the foreign_resource/2 predicate. So, to define a foreign resource exporting the non-static Java method getFactors in the class PrimeNumber in the package numbers, the method/3 term would look like

method('numbers/PrimeNumber','getFactors',[instance])

The syntax for foreign/3 is the basically the same as for C-functions:

foreign(+MethodIdentifier, java, +Predicate)

A hook predicate, specifies the Prolog interface to a Java method. MethodIdentifier is method/3 term as described above. Predicate specifies the name of the Prolog predicate that will be used to call MethodIdentifier. Predicate also specifies how the predicate arguments are to be translated into the corresponding Java arguments.


Node:Conversions between Prolog Arguments and Java Types, Next:, Previous:Calling Java from Prolog, Up:Mixing Java and Prolog

Conversions between Prolog Arguments and Java Types

The following table lists the possible values of arguments of the predicate specification to foreign/3. The value declares which conversion between corresponding Prolog argument and Java type will take place.

NOTE: The conversion declarations (composed of the declarators specified below) together with the method/3 term are used by the glue code generator to create the method's type signature, i.e. a string which can uniquely identify a method within a class. This means that unlike the C interface, the conversion declarations for a Java method will affect the lookup of the method-name (in the C interface, only the function name is relevant). So, if a method is declared as foo(+integer), there must be a method which has the name foo and takes one argument of type int, or an argument which can be automatically converted to an int (a short, for example).

Prolog: +integer
Java: int
The argument should be a number. It is converted to a Java int.
Prolog: +byte
Java: byte
The argument should be a number. It is converted to a Java byte.
Prolog: +short
Java: short
The argument should be a number. It is converted to a Java short.
Prolog: +long
Java: long
The argument should be a number. It is converted to a Java long.

NOTE: Since Java's long type is 64 bits wide and there is no standardized support for 64 bits integers in C, the value will be truncated. So, this declaration is really only useful in order to indicate which method should be used. For example:

class Bar
{
  void foo(int x)
    { ... }

  void foo(long x)
    { ... }
}

In order to be able to indicate that the latter of the foo methods should be called, a +long declaration must be used, even if the value itself will be truncated in the call.

Prolog: +float
Java: float
The argument should be a number. It is converted to a Java float.
Prolog: +double
Java: double
The argument should be a number. It is converted to a Java double.
Prolog: +term
Java: SPTerm
The argument can be any term. It is passed to Java as an object of the class SPTerm.
Prolog: +object(Class)
Java: SPTerm
The argument should be the Prolog representation of a Java object of class Class. Unless it is the first argument in a non-static method (in which case is it treated as the object on which the method should be invoked), it is passed to the Java method as an object of class Class.
Prolog: +atom
Java: SPTerm
The argument should be an atom. The Java method will be passed an object of class SPTerm.
Prolog: +boolean
Java: boolean
The argument should be an atom in {true,false}. The Java method will receive a boolean.
Prolog: +chars
Java: String
The argument should be a list of character codes. The Java method will receive an object of class String.
Prolog: +string
Java: String
The argument should be an atom. The Java method will receive an object of class String.
Prolog: -atom
Java: SPTerm
The argument should be an unbound variable. The Java method will receive an atom of class SPTerm which can be modified. The argument will be bound to the value of the atom when the method returns.
Prolog: -chars
Java: StringBuffer
The argument should be an unbound variable. The Java method will receive an object of type StringBuffer which can be modified. The argument will be bound to a list of the character codes of the StringBuffer object.
Prolog: -string
Java: StringBuffer
The argument should be an unbound variable. The Java method will receive an object of type StringBuffer which can be modified. The argument will be bound to an atom converted from the StringBuffer object.
Prolog: [-integer]
Java: int M()
The Java method should return an int. The value will be converted to a Prolog integer.
Prolog: [-byte]
Java: byte M()
The Java method should return a byte. The value will be converted to a Prolog integer.
Prolog: [-short]
Java: short M()
The Java method should return a short. The value will be converted to a Prolog integer.
Prolog: [-long]
Java: long M()
The Java method should return a long. The value will be converted and possibly truncated to a Prolog integer.
Prolog: [-float]
Java: float M()
The Java method should return a float. The value will be converted to a Prolog float.
Prolog: [-double]
Java: double M()
The Java method should return a double. The value will be converted to a Prolog float.
Prolog: [-term]
Java: SPTerm M()
The Java method should return an object of class SPTerm which will be converted to a Prolog term.
Prolog: [-object(Class)]
Java: SPTerm M()
The Java method should return an object of class Class which will be converted to the internal Prolog representation of the Java object.
Prolog: [-atom]
Java: SPTerm M()
The Java method should return an object of class SPTerm which will be converted to a Prolog atom.
Prolog: [-boolean]
Java: boolean M()
The Java should return a boolean. The value will be converted to a Prolog atom in {true,false}.
Prolog: [-chars]
Java: String M()
The Java method should return an object of class String which will be converted to a list of character codes.
Prolog: [-string]
Java: String M()
The Java method should return an object of class String which will be converted to an atom.


Node:Java-Prolog Example, Previous:Conversions between Prolog Arguments and Java Types, Up:Conversions between Prolog Arguments and Java Types

Calling Java from Prolog: An Example

The following is an simple, but fairly complete example of how a Java method can be called from Prolog.

First, we must write the resource file. Let us call it simple.pl.

% File: simple.pl

:- module(simple, [simple/2]).

:- use_module(library(jasper)).
:- load_foreign_resource(simple).

foreign(method('Simple', 'simpleMethod', [static]), java,
        simple(+integer,[-integer])).

foreign_resource(simple,
                 [
                  method('Simple', 'simpleMethod', [static])
                 ]).

This file is the processed with the script splfr (see Interface Predicates) to produce a foreign resource:

% splfr simple simple.pl
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
{/var/tmp/aaaa004Cd.c generated, 20 msec}

yes

Note that we do not specify any Java files to splfr as we would specify C files when building foreign resources for C code. This is because the C code can be compiled into the resource itself, while the Java code must be loaded at runtime into the JVM. This means that the resource will only contain the glue code for calling the JVM, and no actual Java code. Hence, these resources are usually quite small.

Now, we need some Java code to call:

Simple.java:

public class Simple
{
  static int simpleMethod(int value)
  {
    return value*42;
  }
}

This Java code must now be compiled. Refer to the documentation of your Java implementation exactly how to do this. On Solaris, this might look like:

% javac Simple.java

Now we are ready to call the method simple/2 from inside SICStus.

% sicstus
SICStus 3.8 (SunOS-5.5.1-sparc): Thu Aug 19 16:25:28 MET DST 1999
Licensed to SICS
| ?- compile(simple).
{compiling ...}
[...]
{compiled ... simple.pl in module simple, 160 msec 48640 bytes}

yes
| ?- simple(17,X).

X = 714 ?

yes
| ?-

What has happened is that the predicate simple/2 has been installed as a predicate defined in Java (this is not exactly true; the predicate is defined as a C-function which calls the Java method). When we load the simple module, we will first load the jasper module (and thereby the JVM) and then load the simple foreign resource, which defines the simple/2 predicate.


Node:Calling Prolog from Java, Next:, Previous:Conversions between Prolog Arguments and Java Types, Up:Mixing Java and Prolog

Calling Prolog from Java

Calling Prolog from Java is done by using the Java package jasper. This package contains a set of Java classes which can be used to create and manipulate terms, ask queries and request one or more solutions. The functionality provided by this set of classes is basically the same as the functionality provided by the C-Prolog interface (see Mixing C and Prolog).

The usage is easiest described by an example. The following is a Java version of the train example. See Train.

import se.sics.jasper.*;

public class Simple
{
  public static void main(String argv[]) {

  SICStus sp;
  SPPredicate pred;
  SPTerm from, to, way;
  SPQuery query;
  int i;

  try
    {
      sp = new SICStus(argv,null);

      sp.load("train.ql");

      pred = new SPPredicate(sp, "connected", 4, "");
      to = new SPTerm(sp, "Orebro");
      from = new SPTerm(sp, "Stockholm");
      way = new SPTerm(sp).putVariable();

      query = sp.openQuery(pred, new SPTerm[] { from, to, way, way });

      while (query.nextSolution())
        {
          System.out.println(way.toString());
        }
    }
  catch ( Exception e )
    {
      e.printStackTrace();
    }
  }
}

It is assumed that the reader has read the section on Getting Started, which describes how to get the basics up and running.

This is how the example works:

  1. Before any predicates can be called, the SICStus emulator must be initialized. This is done by instantiating the SICStus class. NOTE: This class must only be instantiated once per Java process. Multiple SICStus-objects are not supported.

    In this example, we have specified null as the second argument to SICStus. This instructs SICStus to search for sprt.sav using its own internal methods, or by passing -Dsicstus.path=[...] to the JVM.

    Most methods take a reference to the SICStus object as their first argument. This is implicit in the rest of this chapter, unless otherwise stated.

  2. The next step is to load the Prolog code. This is done by the method load. Corresponds to SP_load() in the C-interface. See Loading Prolog Code.
  3. Now, everything is set up to start making queries. In order to make a query, the actual query term must be created. This is done by creating an object of the SPPredicate class:
    SPPredicate pred = new SPPredicate(sp, "connected", 4, "");
    
  4. At this point, we have created a predicate object for the predicate connected/4. It is now time to create the arguments for the query. The arguments are placed in an array which is passed to a suitable method to make the query.

    The arguments consist of objects of the class SPTerm. For example, if we need two atoms and a variable for the query

    | ?- connected('Stockholm', 'Orebro', X, X).
    

    the following Java code will do it for us:

    to = new SPTerm(sp, "Orebro");
    from = new SPTerm(sp, "Stockholm");
    way = new SPTerm(sp).putVariable();
    

  5. Now it is time to make the query. As in the C-Prolog interface, there are three ways of making a query.
    query(pred, args)
    This method is useful if you are only interested in finding the first solution to a goal. In the case of connected/4 this is not the case; there are more than one solution.
    queryCutFail(pred, args)
    This method is useful if you are only interested in the side-effects of the query. As query() it only finds the first solution, and then it cuts away all other solutions and fails.
    openQuery(pred, args)
    This method is useful when you are interested in some or all solutions to the query. Since the connected/4 may give us multiple solution, this is what we will use.
    SPQuery query;
    
    query = sp.openQuery(pred, new SPTerm[] { from, to, way, way });
    
    while (query.nextSolution())
      System.out.println(way.toString());
    
    query.close();
    

    The openQuery method returns a reference to the query, an object of the SPQuery class. To obtain solutions, the method nextSolution() is called with no arguments. nextSolution returns true as long as there are more solutions, the example above will print the value of way until there are no more solutions. Observe that the query must be closed, even if nextSolution has indicated that there are no more solutions.


Node:Jasper Package Class Reference, Next:, Previous:Calling Prolog from Java, Up:Mixing Java and Prolog

Jasper Package Class Reference

Detailed documentation of the classes in the jasper package can be found in the HTML documentation installed with SICStus and also at the SICStus documantation page

http://www.sics.se/sicstus/docs/


Node:Exception Handling, Previous:Jasper Package Class Reference, Up:Mixing Java and Prolog

Exception Handling

Exceptions are handled seamlessly between Java and Prolog. This means that exceptions can be thrown in Prolog and caught in Java and the other way around. For example, if a predicate called from Java raises an exception by raise_exception/1 and the predicate itself does not catch the exception, the Java-method which performed the query, queryCutFail() for example, will throw an exception containing the exception term. Symmetrically, a Java-exception thrown (and not caught) in a method called from Prolog will cause the corresponding predicate (simple/2 in the example above) to raise an exception containing the exception object (in the internal Prolog representation of a Java object).


Node:Handling Wide Characters, Next:, Previous:Mixing Java and Prolog, Up:Top

Handling Wide Characters

The chapter describes the SICStus Prolog features for handling wide characters. We will refer to these capabilities as Wide Character eXtensions, and will use the abbreviation WCX.


Node:WCX Introduction, Next:, Previous:Handling Wide Characters, Up:Handling Wide Characters

Introduction

SICStus Prolog supports character codes up to 31 bits wide. It has a set of hooks for specifying how the character codes should be read in and written out to streams, how they should be classified (as letters, symbol-chars, etc.), and how strings of wide characters should be exchanged with the operating system. There are three sets of predefined hook functions supporting ISO 8859/1, UNICODE/UTF-8 and EUC external encodings, selectable using an environment variable. Alternatively, users may plug in their own definition of hook functions and implement arbitrary encodings. WCX Concepts, introduces the basic WCX concepts and presents their implementation in SICStus Prolog. Prolog Level WCX Features, gives an overview of those Prolog language features which are affected by wide character handling. WCX Environment Variables, and WCX Hooks, describe the options for customization of SICStus Prolog WCX through environment variables and through the hook functions, respectively. WCX Foreign Interface, and WCX Features in Libraries, summarize the WCX extensions in the foreign language interface and in the libraries. WCX Utility Functions, describes the utility functions provided by SICStus Prolog to help in writing the WCX hook functions, while Representation of EUC Wide Characters, presents the custom-made internal code-set for the EUC encoding. Finally A Sample WCX Box, describes an example implementation of the WCX hook functions, which supports a composite character code set and four external encodings. The code for this example is included in the distribution as library(wcx_example).


Node:WCX Concepts, Next:, Previous:WCX Introduction, Up:Handling Wide Characters

Concepts

First let us introduce some notions concerning wide characters.

(Wide) character code
an integer, possibly outside the 0..255 range.

SICStus Prolog allows character codes in the range 0..2147483647 (= 2^31-1). Consequently, the built-in predicates for building and decomposing atoms from/into character codes (e.g., atom_codes/2, name/2, etc.) accept and produce lists of integers in the above range (excluding the 0 code).

Wide characters can be used in all contexts: in atoms (single quoted, or unquoted, depending on the character-type mapping), strings, character code notation (0'char), etc.

External (stream) encoding
a way of encoding sequences of wide characters as sequences of (8-bit) bytes, used in stream input and output.

SICStus Prolog has three different external stream encoding schemes built-in, selectable through an environment variable. Furthermore it provides hooks for users to plug in their own external stream encoding functions. The built-in predicates put_code/1, get_code/1, etc. accept and return wide character codes, converting the bytes written or read using the external encoding in force.

Note that an encoding need not be able to handle the whole range of character codes allowed by SICStus Prolog.

Character code set
a subset of the set {0, ..., 2^31-1} that can be handled by an external encoding. SICStus Prolog assumes that the character code set is an extension of the ASCII code set, i.e. it includes codes 0..127, and these codes are interpreted as ASCII characters. Note that ASCII characters can still have an arbitrary external encoding, cf. the usage flag WCX_CHANGES_ASCII, see WCX Hooks.
Character type mapping
a function mapping each element of the character code set to one of the character categories (layout, small-letter, symbol-char, etc. see Token String). This is required for parsing tokens. The character-type mapping for non-ASCII characters is hookable in SICStus Prolog and has three built-in defaults, depending on the external encoding selected.
System encoding
a way of encoding wide character strings, used or required by the operating system environment in various contexts (e.g. file names in open/3, command line options, as returned by prolog_flag(argv, Flags), etc.). The system encoding is hookable in SICStus Prolog and has two built-in defaults.
Internal encoding
a way of encoding wide character strings internally within the SICStus Prolog system. This is of interest to the user only if the foreign language interface is used in the program, or a system encoding hook function needs to be written. SICStus Prolog has a fixed internal encoding, which is UTF-8.

As discussed above there are several points where the users can influence the behavior of SICStus Prolog. The user can decide on

Let us call WCX mode a particular setting of these parameters.

Note that the selection of the character code set is conceptual only and need not be communicated to SICStus Prolog, as the decision materializes in the functions for the mapping and encodings.


Node:Prolog Level WCX Features, Next:, Previous:WCX Concepts, Up:Handling Wide Characters

Summary of Prolog level WCX features

SICStus Prolog has a Prolog flag, called wcx, whose value can be an arbitrary atom, and which is initialized to []. This flag is used at opening a stream, its value is normally passed to a user-defined hook function. This can be used to pass some information from Prolog to the hook function. In the example of A Sample WCX Box, which supports the selection of external encodings on a stream-by-stream basis, the value of the wcx flag is used to specify the encoding to be used for the newly opened stream.

The value of the wcx flag can be overridden by supplying a wcx(Value) option to open/4 and load_files/2. If such an option is present, then the Value is passed on to the hook function.

The wcx flag has a reserved value. The value wci (wide character internal encoding) signifies that the stream should use the SICStus Prolog internal encoding (UTF-8), bypassing the hook functions supplied by the user. This is appropriate, e.g., if a file with wide characters is to be produced, which has to be readable irrespective of the (possibly user supplied) encoding scheme.

Wide characters generally require several bytes to be input or output. Therefore, for each stream, SICStus Prolog keeps track of the number of bytes input or output, in addition to the number of (wide) characters. Accordingly there is a built-in predicate byte_count(+Stream,?N) for accessing the number of bytes read/written on a stream.

Note that the predicate character_count/2 returns the number of characters read or written, which may be less than the number of bytes, if some of the characters are multibyte. (On output streams the byte_count/2 can also be less than the character_count/2, if some codes, not belonging to the code-set handled, are not written out.)

Note that if a stream is opened as a binary stream:

open(..., ..., ..., [type(binary)])

then no wide character handling will take place; every character output will produce a single byte on the stream, and every byte input will be considered a separate character.


Node:WCX Environment Variables, Next:, Previous:Prolog Level WCX Features, Up:Handling Wide Characters

Selecting the WCX mode using environment variables

When the SICStus Prolog system starts up, its WCX mode is selected according to the value of the SP_CTYPE environment variable. The supported values of the SP_CTYPE environment variable are the following:

iso_8859_1 (default)

character code set:
0..255
character-type mapping:
according to the ISO 8859/1 standard, see Token String.
external encoding:
each character code is mapped to a single byte on the stream with the same value (trivial encoding).

utf8

character code set:
0..2147483647 (= 2^31-1)
character-type mapping:
according to ISO 8859/1 for codes 0..255. All codes above 255 are considered small-letters.
external encoding:
UTF-8

This WCX mode is primarily intended to support the UNICODE character set, but it also allows the input and output of character codes above the 16-bit UNICODE character code range.

euc

character code set:
a subset of 0..8388607 The exact character code set is described in Representation of EUC Wide Characters, together with its mapping to the standard external encoding.
character-type mapping:
according to ISO 8859/1 for codes 0..127. All codes above 127 are considered small-letters.
external encoding:
EUC encoding with the lengths of the sub-code-sets dependent on the locale.

In all three cases the system encoding is implemented as truncation to 8-bits, i.e. any code output to the operating system is taken modulo 256, any byte coming from the operating system is mapped to the code with the same value.

The figure below shows an example interaction with SICStus Prolog in EUC mode. For the role of the SP_CSETLEN environment variable, see Representation of EUC Wide Characters.

images/kterm.png

SICStus Prolog in EUC mode


Node:WCX Hooks, Next:, Previous:WCX Environment Variables, Up:Handling Wide Characters

Selecting the WCX mode using hooks

Users can have complete control over the way wide characters are handled by SICStus Prolog if they supply their own definitions of appropriate hook functions. A set of such functions, implementing a specific environment for handling wide characters is called a WCX box. A sample WCX box is described below (see A Sample WCX Box).

Plugging-in of the WCX hook functions can be performed by calling

void SP_set_wcx_hooks ( int usage,
                        SP_WcxOpenHook *wcx_open,
                        SP_WcxCloseHook *wcx_close,
                        SP_WcxCharTypeHook *wcx_chartype,
                        SP_WcxConvHook *wcx_from_os,
                        SP_WcxConvHook *wcx_to_os);

The effect of SP_set_wcx_hooks() is controlled by the value of usage. The remaining arguments are pointers to appropriate hook functions or NULL values, the latter implying that the hook should take some default value.

There are three independent aspects to be controlled, and usage should be supplied as a bitwise OR of chosen constant names for each aspect. The defaults have value 0, so need not be included. The aspects are the following:

  1. decide on the default code-set

    This decides the default behavior of the wcx_open and wcx_chartype hook functions (if both are supplied by the user, the choice of the default is irrelevant). The possible values are:


    WCX_USE_LATIN1 (default)
    WCX_USE_UTF8
    WCX_USE_EUC
    Select the behavior described above under titles iso_8859_1, utf8, and euc, respectively; see WCX Environment Variables.

  2. decide on the default system encoding

    The flags below determine what function to use for conversion from/to the operating system encoding, if such functions are not supplied by the user through the wcx_from_os and wcx_to_os arguments (if both are supplied by the user, the choice of default is irrelevant).


    WCX_OS_8BIT (default)
    Select the "truncation to 8-bits" behavior.
    WCX_OS_UTF8
    Select the UTF-8 encoding to be used for all communication with the operating system.

  3. decide on the preservation of ASCII, i.e., the codes in 0..127

    This is important if some of the conversion functions (wcx_from_os, wcx_to_os, and wcx_getc, wcx_putc, see later) are user-defined. In such cases it may be beneficial for the user to inform SICStus Prolog whether the supplied encoding functions preserve ASCII characters. (The default encodings do preserve ASCII.)


    WCX_PRESERVES_ASCII (default)
    Declare that the encodings preserve all ASCII characters, i.e. getting or putting an ASCII character need not go through the conversion functions, and for strings containing ASCII characters only, the system encoding conversions need not be invoked.
    WCX_CHANGES_ASCII
    Force the system to use the conversion functions even for ASCII characters and strings.

We now describe the role of the arguments following usage in the argument list of SP_set_wcx_hooks().

SP_WcxOpenHook *wcx_open
where typedef void (SP_WcxOpenHook) (SP_stream *s, unsigned long option, int context);

This function is called by SICStus Prolog for each s stream opened, except when the encoding to be used for the stream is pre-specified (binary files, files opened using the wci option, and the C streams created with contexts SP_STREAMHOOK_WCI and SP_STREAMHOOK_BIN).

The main task of the wcx_open hook is to associate the two WCX-processing functions with the stream, by storing them in the appropriate fields of the SP_stream data structure:

SP_WcxGetcHook *wcx_getc;
SP_WcxPutcHook *wcx_putc;
    

These fields are pointers to the functions performing the external decoding and encoding as described below. They are initialized to functions that truncate to 8 bits on output and zero-extend to 31 bits on input.


SP_WcxGetcHook *wcx_getc
where typedef int (SP_WcxGetcHook) (int first_byte, SP_stream *s, long *pbyte_count);

This function is generally invoked whenever a character has to be read from a stream. Before invoking this function, however, a byte is read from the stream by SICStus Prolog itself. If the byte read is an ASCII character (its value is < 128), and WCX_PRESERVES_ASCII is in force, then the byte read is deemed to be the next character code, and wcx_getc is not invoked. Otherwise, wcx_getc is invoked with the byte and stream in question and is expected to return the next character code.

The wcx_getc function may need to read additional bytes from the stream, if first byte signifies the start of a multi-byte character. A byte may be read from the stream s in the following way:

byte = s->sgetc((long)s->user_handle);
        

The wcx_getc function is expected to increment its *pbyte_count argument by 1 for each such byte read.

The default wcx_open hook will install a wcx_getc function according to the usage argument. The three default external decoding functions are also available to users through the SP_wcx_getc() function (see WCX Utility Functions).

SP_WcxPutcHook *wcx_putc
where typedef int (SP_WcxPutcHook) (int char_code, SP_stream *s, long *pbyte_count);

This function is generally invoked whenever a character has to be written to a stream. However, if the character code to be written is an ASCII character (its value is < 128), and WCX_PRESERVES_ASCII is in force, then the code is written directly on the stream, and wcx_putc is not invoked. Otherwise, wcx_putc is invoked with the character code and stream in question and is expected to do whatever is needed to output the character code to the stream.

This will require outputting one or more bytes to the stream. A byte byte can be written to the stream s in the following way:

return_code = s->sputc(byte,(long)s->user_handle);
        

The wcx_putc function is expected to return the return value of the last invocation of s->sputc, or -1 as an error code, if incapable of outputting the character code. The latter may be the case, for example, if the code to be output does not belong to the character code set in force. It is also expected to increment its *pbyte_count argument by 1 for each byte written.

The default wcx_open hook function will install a wcx_putc function according to the usage argument. The three default external encoding functions are also available to users through the SP_wcx_putc() function (see WCX Utility Functions).

In making a decision regarding the selection of these WCX-processing functions, the context and option arguments of the wcx_open hook can be used. The context argument encodes the context of invocation. It is one of the following values


SP_STREAMHOOK_STDIN
SP_STREAMHOOK_STDOUT
SP_STREAMHOOK_STDERR
for the three standard streams,
SP_STREAMHOOK_OPEN
for streams created by open
SP_STREAMHOOK_NULL
for streams created by open_null_stream
SP_STREAMHOOK_LIB
for streams created from the libraries
SP_STREAMHOOK_C, SP_STREAMHOOK_C+1, ...
for streams created from C code via SP_make_stream()

The option argument comes from the user and it can carry some WCX-related information to be associated with the stream opened. For example, this can be used to implement a scheme supporting multiple encodings, supplied on a stream-by-stream basis, as shown in the sample WCX-box (see A Sample WCX Box).

If the stream is opened from Prolog code, the option argument for this hook function is derived from the wcx(Option) option of open/4 and load_files/2. If this option is not present, or the stream is opened using some other built-in, then the value of the wcx prolog flag will be passed on to the open hook.

If the stream is opened from C, via SP_make_stream(), then the option argument will be the value of the prolog flag wcx.

There is also a variant of SP_make_stream(), called SP_make_stream_context() which takes two additional arguments, the option and the context, to be passed on to the wcx_open hook (see WCX Foreign Interface).

The wcx_open hook can associate the information derived from option with the stream in question using a new field in the SP_stream data structure: void *wcx_info, initialized to NULL. If there is more information than can be stored in this field, or if the encoding to be implemented requires keeping track of a state, then the wcx_open hook should allocate sufficient amount of memory for storing the information and/or the state, using SP_malloc(), and deposit a pointer to that piece of memory in wcx_info.

The default wcx_open hook function ignores its option and context arguments and sets the wcx_getc and wcx_putc stream fields to functions performing the external decoding and encoding according to the usage argument of SP_set_wcx_hooks().

SP_WcxCloseHook *wcx_close
where typedef void (SP_WcxCloseHook) (SP_stream *s);

This hook function is called whenever a stream is closed, for which the wcx_open hook was invoked at its creation. The argument s points to the stream being closed. It can be used to implement the closing activities related to external encoding, e.g. freeing any memory allocated in wcx_open hook.

The default wcx_close hook function does nothing.

SP_WcxCharTypeHook *wcx_chartype
where typedef int (SP_WcxCharTypeHook) (int char_code);

This function should be prepared to take any char_code >= 128 and return one of the following constants:


CHT_LAYOUT_CHAR
for additional characters in the syntactic category layout-char,
CHT_SMALL_LETTER
for additional characters in the syntactic category small-letter,
CHT_CAPITAL_LETTER
for additional characters in the syntactic category capital-letter,
CHT_SYMBOL_CHAR
for additional characters in the syntactic category symbol-char,
CHT_SOLO_CHAR
for additional characters in the syntactic category solo-char.

Regarding the meaning of these syntactic categories, see Token String.

The value returned by this function is not expected to change over time, therefore, for efficiency reasons, its behavior is cached. The cache is cleared by SP_set_wcx_hooks().

As a help in implementing this function, SICStus Prolog provides the function SP_latin1_chartype(), which returns the character type category for the codes 1..255 according to the ISO 8859/1 standard.

Note that if a character code >= 512 is categorized as a layout-char, and a character with this code occurs within an atom being written out in quoted form (e.g. using writeq) in native sicstus mode (as opposed to iso mode), then this code will be output as itself, rather than an octal escape sequence. This is because in sicstus mode escape sequences consist of at most 3 octal digits.

SP_WcxConvHook *wcx_to_os
where typedef char* (SP_WcxConvHook) (char *string, int context);

This function is normally called each time SICStus Prolog wishes to communicate a string of possibly wide characters to the operating system. However, if the string in question consists of ASCII characters only, and WCX_PRESERVES_ASCII is in force, then wcx_to_os may not be called, and the original string may be passed to the operating system.

The first argument of wcx_to_os is a zero terminated string, using the internal encoding of SICStus Prolog, namely UTF-8. The function is expected to convert the string to a form required by the operating system, in the context described by the second, context argument, and to return the converted string. The conversion should be done in a memory area controlled by this function (preferably a static buffer, reused each time the function is called).

The second argument specifies the context of conversion. It can be one of the following integer values:


WCX_FILE
the string is a file-name,
WCX_OPTION
the string is a command, a command line argument or an environment variable,
WCX_WINDOW_TITLE
the string is a window title,
WCX_C_CODE
the string is a C identifier (used, e.g., in the glue code)

SICStus Prolog provides a utility function SP_wci_code(), see below, for obtaining a wide character code from a UTF-8 encoded string, which can be used to implement the wcx_to_os hook function.

The default of the wcx_to_os function depends on the usage argument of SP_set_wcx_hooks(). If the value of usage includes WCX_OS_UTF8, then the function does no conversion, as the operating system uses the same encoding as SICStus Prolog. If the value of usage includes WCX_OS_8BIT, then the function decodes the UTF-8 encoded string and converts this sequence of codes into a sequence of bytes by truncating each code to 8 bits.

Note that the default wcx_to_os functions ignore their context argument.

SP_WcxConvHook *wcx_from_os
where typedef char* (SP_WcxConvHook) (char *string, int context);

This function is called each time SICStus Prolog receives from the operating system a zero terminated sequence of bytes possibly encoding a wide character string. The function is expected to convert the byte sequence, if needed, to a string in the internal encoding of SICStus Prolog (UTF-8), and return the converted string. The conversion should be done in a memory area controlled by this function (preferably a static buffer, reused each time the function is called, but different from the buffer used in wcx_to_os).

The second argument specifies the context of conversion, as in the case of wcx_to_os.

SICStus Prolog provides a utility function SP_code_wci(), see below, for converting a character code (up to 31 bits) into UTF-8 encoding, which can be used to implement the wcx_from_os hook function.

The default of the wcx_from_os function depends on the usage argument of SP_set_wcx_hooks(). If the value of usage includes WCX_OS_UTF8, then the function does no conversion. If the value of usage includes WCX_OS_8BIT, then the function transforms the string of 8-bit codes into an UTF-8 encoded string.

Note that the default wcx_from_os functions ignore their context argument.


Node:WCX Foreign Interface, Next:, Previous:WCX Hooks, Up:Handling Wide Characters

Summary of WCX features in the foreign interface

All strings passed to foreign code, or expected from foreign code, which correspond to atoms or lists of character codes on the Prolog side, are in the internal encoding form, UTF-8. Note that this is of concern only if the strings contain non-ASCII characters (e.g. accented letters in the latin1 encoding).

Specifically, the C arguments corresponding to the following foreign specifications are passed and received as strings in the internal encoding:

+chars +string +string(N)
-chars -string -string(N)
[-chars] [-string] [-string(N)]

Similarly, the following functions defined in the foreign interface expect and deliver internally encoded strings in their char * and char ** arguments.

int SP_put_string(SP_term_ref t, char *name)
int SP_put_list_chars(SP_term_ref t, SP_term_ref tail, char *s)
int SP_put_list_n_chars(SP_term_ref t, SP_term_ref tail,
                    long n, char *s)
int SP_get_string(SP_term_ref t, char **name)
int SP_get_list_chars(SP_term_ref t, char **s)
int SP_get_list_n_chars(SP_term_ref t, SP_term_ref tail,
                    long n, long *w, char *s)
void SP_puts(char *string)
void SP_fputs(char *string, SP_stream *s)
int  SP_printf(char *format, ...)
int  SP_fprintf(SP_stream *s, char *format, ...)
unsigned long SP_atom_from_string(char *s)
char *SP_string_from_atom(unsigned long a)
SP_pred_ref SP_predicate(char *name_string,
                     long arity,
                     char *module_string)
int SP_load(char *filename)
int SP_restore(char *filename)

The following functions deliver or accept wide character codes (up to 31 bits), and read or write them on the appropriate stream in the external encoding form:

int  SP_getc(void)
int  SP_fgetc(SP_stream *s)
void SP_putc(int c)
void SP_fputc(int c, SP_stream *s)

In the following function, strings are expected in the encoding format relevant for the operating system:

int SP_initialize(int argc, char **argv, char *boot_path)

Here argv is an array of strings, as received from the operating system. These strings will be transformed to internal form using the wcx_from_os(WCX_OPTION,...) hook function. Also boot_path is expected to be in the format file names are encoded, and wcx_from_os(WCX_FILE,...) will be used to decode it.

There are other functions in the foreign interface that take or return strings. For these, the encoding is not relevant, either because the strings are guaranteed to be ASCII (SP_error_message(), SP_put_number_chars(), SP_get_number_chars()), or because the strings in question have no relation to Prolog code, as in SP_on_fault(), SP_raise_fault().

The SP_make_stream_context() foreign interface function is a variant of SP_make_stream() with two additional arguments: option and context. This extended form can be used to create streams from C with specified WCX features.

The context argument the SP_make_stream_context function can be one of the following values:

SP_STREAMHOOK_WCI
SP_STREAMHOOK_BIN
SP_STREAMHOOK_C, SP_STREAMHOOK_C+1, ...

SP_STREAMHOOK_WCI means that input and output on the given stream should be performed using the SICStus internal encoding scheme, UTF-8, while SP_STREAMHOOK_BIN indicates that no encoding should be applied (binary files).

In the last two cases the wcx_open hook will not be called. In all other cases SP_make_stream_context will call the wcx_open hook function, with the option and context supplied to it. The option argument of SP_make_stream_context can be the standard representation of a Prolog atom, or the constant SP_WCX_FLAG, which prescribes that the value of the prolog flag wcx should be supplied to the open hook function.

The user may add further context constants for his own use, with values greater than SP_STREAMHOOK_C.


Node:WCX Features in Libraries, Next:, Previous:WCX Foreign Interface, Up:Handling Wide Characters

Summary of WCX-related features in the libraries

Some libraries are affected by the introduction of wide characters.

When using library(jasper) SICStus Prolog properly receives non-ASCII strings from Java, and similarly, non-ASCII strings can be correctly passed to Java. This is in contrast with versions of SICStus Prolog earlier then 3.8 (i.e. without the WCX extensions), where, for example, strings containing non-ASCII characters passed from Java to Prolog resulted in an UTF-8 encoded atom or character code list on the Prolog side.

Several predicates in libraries sockets, system and tcltk create streams. These now use the SP_make_stream_context() function, with SP_WCX_FLAG as the option and the relevant SP_STREAMHOOK_LIB constant as the context argument. For example, if the WCX mode is set using environment variables (see WCX Environment Variables), then this implies that the selected encoding will be used for streams created in the libraries. E.g., if the SP_CTYPE environment variable is set to utf8, then the output of non-ASCII characters to a socket stream will be done using UTF-8 encoding. If a wcx_open hook is supplied, then the user is free to select a different encoding for the libraries, as he is informed about the stream being opened by a library through the context argument of the wcx_open function.

Some of the arguments of library predicates contain atoms which are file names, environment variable names, commands, etc. If these contain non-ASCII characters, then they will be passed to the appropriate operating system function following a conversion to the system encoding in force (wcx_to_os hook), and similarly such atoms coming from the OS functions undergo a conversion from system encoding (wcx_from_os). Note however that host names (e.g. in system:host_name(S)) are assumed to be consisting of ASCII characters only.


Node:WCX Utility Functions, Next:, Previous:WCX Features in Libraries, Up:Handling Wide Characters

WCX related utility functions

The default functions for reading in and writing out character codes using one of the three supported encodings are available through

SP_WcxGetcHook *SP_wcx_getc(int usage);
SP_WcxPutcHook *SP_wcx_putc(int usage);

These functions return the decoding/encoding functions appropriate for usage, where the latter is one of the constants WCX_USE_LATIN1, WCX_USE_UTF8, WCX_USE_EUC.

The following utility functions may be useful when dealing with wide characters in internal encoding (WCI). These functions are modeled after multibyte character handling functions of Solaris.

int SP_wci_code(int *pcode, char *wci);

SP_wci_code() determines the number of bytes that comprise the internally encoded character pointed to by wci. Also, if pcode is not a null pointer, SP_wci_code() converts the internally encoded character to a wide character code and places the result in the object pointed to by pcode. (The value of the wide character corresponding to the null character is zero.) At most WCI_MAX_BYTES bytes will be examined, starting at the byte pointed to by wci.

If wci is a null pointer, SP_wci_code() simply returns 0. If wci is not a null pointer, then, if wci points to the null character, SP_wci_code() returns 0; if the next bytes form a valid internally encoded character, SP_wci_code() returns the number of bytes that comprise the internal encoding; otherwise wci does not point to a valid internally encoded character and SP_wci_code() returns the negated length of the invalid byte sequence. This latter case can not happen, if wci points to the beginning of a Prolog atom string, or to a position within such a string reached by repeated stepping over correctly encoded wide characters.


WCI_MAX_BYTES
WCI_MAX_BYTES is a constant defined by SICStus Prolog showing the maximal length (in bytes) of the internal encoding of a single character code. (As the internal encoding is UTF-8, this constant has the value 6).

int SP_wci_len(char *wci);

SP_wci_len() determines the number of bytes comprising the multi-byte character pointed to by wci. It is equivalent to:

SP_wci_code((int *)0, wci);
  

int SP_code_wci(char *wci, int code);

SP_code_wci() determines the number of bytes needed to represent the internal encoding of the character code, and, if wci is not a null pointer, stores the internal encoding in the array pointed to by wci. At most WCI_MAX_BYTES bytes are stored.

SP_code_wci() returns -1 if the value of code is outside the wide character code range; otherwise it returns the number of bytes that comprise the internal encoding of code.

int SP_latin1_chartype(int char_code);

SP_latin1_chartype returns the character type category of the character code char_code, according to the ISO 8859/1 code-set. The char_code value is assumed to be in the 1..255 range.


Node:Representation of EUC Wide Characters, Next:, Previous:WCX Utility Functions, Up:Handling Wide Characters

Representation of EUC wide characters

As opposed to UNICODE, the definition of EUC specifies only the external representation. The actual wide character codes assigned to the multibyte characters are not specified. UNIX systems supporting EUC have their own C data type, wchar_t, which stores a wide character, but the mapping between this type and the external representation is not standardized.

We have decided to use a custom made mapping from the EUC encoding to the character code set, as opposed to using the UNIX type wchar_t. This decision was made so that the code set is machine independent and results in a compact representation of atoms.

EUC consists of four sub-code-sets, three of which can have multibyte external representation. Sub-code-set 0 consists of ASCII characters and is mapped one-to-one to codes 0..127. Sub-code-set 1 has an external representation of one to three bytes in the range 128-255, the length determined by the locale. Sub-code-sets 2 and 3 are similar, but their external representation is started by a so called single shift character code, known as SS2 and SS3, respectively. The following table shows the mapping from the EUC external encoding to SICStus Prolog character codes.

Sub-
code-set  External encoding                 Character code (binary)

 0        0xxxxxxx                          00000000 00000000 0xxxxxxx

 1        1xxxxxxx                          00000000 00000000 1xxxxxxx
          1xxxxxxx 1yyyyyyy                 00000000 xxxxxxx0 1yyyyyyy
          1xxxxxxx 1yyyyyyy 1zzzzzzzz       0xxxxxxx yyyyyyy0 1zzzzzzz

 2        SS2 1xxxxxxx                      00000000 00000001 0xxxxxxx
          SS2 1xxxxxxx 1yyyyyyy             00000000 xxxxxxx1 0yyyyyyy
          SS2 1xxxxxxx 1yyyyyyy 1zzzzzzzz   0xxxxxxx yyyyyyy1 0zzzzzzz

 3        SS3 1xxxxxxx                      00000000 00000001 1xxxxxxx
          SS3 1xxxxxxx 1yyyyyyy             00000000 xxxxxxx1 1yyyyyyy
          SS3 1xxxxxxx 1yyyyyyy 1zzzzzzzz   0xxxxxxx yyyyyyy1 1zzzzzzz

For sub-code-sets other than 0, the sub-code-set length indicated by the locale determines which of three mappings are used (but see below the SP_CSETLEN environment variable). When converting SICStus Prolog character codes to EUC on output, we ignore bits that have no significance in the mapping selected by the locale.

The byte lengths associated with the EUC sub-code-sets are determined by using the csetlen() function. If this function is not available in the system configuration used, then Japanese Solaris lengths are assumed, namely 2, 1, 2 for sub-code-sets 1, 2, and 3, respectively (the lengths exclude the single shift character).

To allow experimentation with sub-code-sets differing from the locale, the sub-code-set length values can be overridden by setting the SP_CSETLEN environment variable to xyz, where x, y, and z are digits in the range 1..3. Such a setting will cause the sub-code-sets 1, 2, 3 to have x, y, and z associated with them as their byte lengths.


Node:A Sample WCX Box, Previous:Representation of EUC Wide Characters, Up:Handling Wide Characters

A sample Wide Character Extension (WCX) box

This example implements a WCX box supporting the use of four external encodings within the same SICStus Prolog invocation: ISO Latin1, ISO Latin2 (ISO 8859/2), UNICODE, and EUC. The code is included in the distribution as library(wcx_example).

The default encoding functions supplied in SICStus Prolog deal with a single encoding only. However, the interface does allow the implementation of WCX boxes supporting different encodings for different streams.

A basic assumption in SICStus Prolog is that there is a single character set. If we are to support multiple encodings we have to map them into a single character set. For example, the single-byte character sets ISO Latin1 and ISO Latin2 can be easily mapped to the Unicode character set. On the other hand there does not seem to be a simple mapping of the whole of EUC character set to UNICODE or the other way round.

Therefore, in this example, we use a composite character set, which covers both EUC and Unicode, but does not deal with unifying the character codes of characters which appear in both character sets, except for the case of ASCII characters.

The figure below depicts the structure of the composite character set of the sample WCX box.

.------------------.
|  EUC             |
|                  |
|                  |
|        .+++++++++++++++++++++++++++.
|        +  ASCII  *  LATIN1  |      +
.--------+=========*==========       +
         + LATIN2  *                 +
         +**********                 +
         +                           +
         +                           +
         +                 UNICODE   +
         .+++++++++++++++++++++++++++.

This character code set uses character codes up to 24 bit wide:

0 =< code =< 2^16-1
A UNICODE character with the given code, including ASCII.
code = 2^16 + euc_code
A non-ASCII EUC character with code euc_code (as described in Representation of EUC Wide Characters).

The four external encodings supported by the sample WCX box can be specified on a stream-by-stream basis, by supplying a wcx(ENC) option to open/4, where ENC is one of the atoms latin1, latin2, unicode or euc.

The mapping of these external encodings to the composite character code set is done in the following way:

latin1
is mapped one-to-one to UNICODE codes 0x0..0xff
latin2
is mapped to UNICODE codes 0x0..0x02dd, using an appropriate conversion table for the non-ASCII part.
unicode
assumes UTF-8 external encoding and maps one-to-one to the 0x0..0xffff UNICODE range.
euc
assumes EUC external encoding and maps sub-code-set 0 to UNICODE range 0x0..0x7f, and sub-code-sets 1-3 to internal codes above 0xffff, as shown above.

Note that in order to support this composite character code set, we had to give up the ability to read and write UTF-8-encoded files with character codes above 0xffff (which is possible using the built-in utf8 WCX-mode of SICStus Prolog, (see Prolog Level WCX Features)).

The example uses a primitive character-type mapping: characters in the 0x80-0xff range are classified according to the latin1 encoding, above that range all characters are considered small-letters. However, as an example of re-classification, code 0xa1 (inverted exclamation mark) is categorized as solo-char.

The default system encoding is used (truncate to 8-bits).

The box has to be initialized by calling the C function wcx_setup(), which first reads the environment variable WCX_TYPE, and uses its value as the default encoding. It then calls SP_set_wcx_hooks(), and initializes its own conversion tables. In a runtime system wcx_setup() should be called before SP_initialize(), so that it effects the standard streams created there. The second phase of initialization, wcx_init_atoms(), has to be called after SP_initialize(), to set up variables storing the atoms naming the external encodings.

In a development system the two initialization phases can be put together, this is implemented as wcx_init(), and is declared to be a foreign entry point in wcx.pl.

On any subsequent creation of a stream, the hook function my_wcx_open() is called. This sets the wide character get and put function pointers in the stream according to the atom supplied in the wcx(...) option, or according to the value of the prolog flag wcx.

Within the put function it may happen that a character code is to be output, which the given encoding cannot accommodate (a non-ASCII Unicode character on an EUC stream or vice-versa). No bytes are output in such a case and -1 is returned as an error code.

There is an additional foreign C function implemented in the sample WCX box: wcx_set_encoding(), available from Prolog as set_encoding/2. This allows changing the encoding of an already open stream. This is used primarily for standard input-output streams, while experimenting with the box.


Node:Example Intro, Next:, Previous:Handling Wide Characters, Up:Top

Programming Tips and Examples

This chapter describes how to write clean programs that will execute efficiently. To some extent, writing efficient code in any language requires basic knowledge of its compiler, and we will mention some important properties of the SICStus Prolog compiler. A number of simple examples of Prolog programming are also given.


Node:Programming Guidelines, Next:, Previous:Example Intro, Up:Example Intro

Programming Guidelines

A lot of clarity and efficiency is gained by sticking to a few basic rules. This list is necessarily very incomplete. The reader is referred to textbooks such as [O'Keefe 90] for a thorough exposition of the elements of Prolog programming style and techniques.


Node:Indexing, Next:, Previous:Programming Guidelines, Up:Example Intro

Indexing

The clauses of any predicate are indexed according to the principal functor of the first argument in the head of the clause. This means that the subset of clauses which match a given goal, as far as the first step of unification is concerned, is found very quickly, in practically constant time. This can be very important where there is a large number of clauses for a predicate. Indexing also improves the Prolog system's ability to detect determinacy--important for conserving working storage, and strongly related to last call optimization (see below).

Indexing applies to interpreted clauses as well as to compiled clauses.


Node:Tail, Next:, Previous:Indexing, Up:Example Intro

Last Call Optimization

The compiler incorporates last call optimization to improve the speed and space efficiency of determinate predicates.

When execution reaches the last goal in a clause belonging to some predicate, and provided there are no remaining backtrack points in the execution so far of that predicate, all of the predicate's local working storage is reclaimed before the final call, and any terms it has created become eligible for garbage collection. This means that programs can now recurse to arbitrary depths without necessarily exceeding core limits. For example:

cycle(State) :- transform(State, State1), cycle(State1).

where transform/2 is a determinate predicate, can continue executing indefinitely, provided each individual term, State, is not too large. The predicate cycle is equivalent to an iterative loop in a conventional language.

To take advantage of last call optimization one must ensure that the Prolog system can recognize that the predicate is determinate at the point where the recursive call takes place. That is, the system must be able to detect that there are no other solutions to the current goal to be found by subsequent backtracking. In general this involves reliance on the Prolog compiler's indexing and/or use of cut; see Cut.


Node:If-Then-Else, Next:, Previous:Tail, Up:Example Intro

If-Then-Else Compilation

Ordinary disjunction, (P;Q), is treated by the compiler as an anonymous predicate with two clauses, and the execution of a disjunction relies on backtracking to explore the two disjuncts.

If-then-else statements of the form:

(If -> Then; Else)

are recognized by the compiler and are under certain conditions compiled to code that is much more efficient than the corresponding disjunction, essentially turning the If test to a conditional jump and often avoiding costly backtracking altogether.

For this optimization to be effective, the test must be a conjunction of a restricted set of built-in predicates (roughly, arithmetic tests, type tests and term comparisons).

This optimization is actually somewhat more general than what is described above. A sequence of guarded clauses:

Head1 :- Guard1, !, Body1.
...
Headm :- Guardm, !, Bodym.
Headn :- Bodym.

is eligible for the same optimization, provided that the arguments of the clause heads are all unique variables and that the "guards" are simple tests as described above.


Node:Programming Examples, Previous:If-Then-Else, Up:Example Intro

Programming Examples

The rest of this chapter contains a number of simple examples of Prolog programming, illustrating some of the techniques described above.


Node:Simple List, Next:, Previous:Programming Examples, Up:Programming Examples

Simple List Processing

The goal concatenate(L1,L2,L3) is true if list L3 consists of the elements of list L1 concatenated with the elements of list L2. The goal member(X,L) is true if X is one of the elements of list L. The goal reverse(L1,L2) is true if list L2 consists of the elements of list L1 in reverse order.

concatenate([], L, L).
concatenate([X|L1], L2, [X|L3]) :- concatenate(L1, L2, L3).

member(X, [X|_]).
member(X, [_|L]) :- member(X, L).

reverse(L, L1) :- reverse_concatenate(L, [], L1).

reverse_concatenate([], L, L).
reverse_concatenate([X|L1], L2, L3) :-
        reverse_concatenate(L1, [X|L2], L3).


Node:Family Example, Next:, Previous:Simple List, Up:Programming Examples

Family Example (descendants)

The goal descendant(X,Y) is true if Y is a descendant of X.

descendant(X, Y) :- offspring(X, Y).
descendant(X, Z) :- offspring(X, Y), descendant(Y, Z).

offspring(abraham, ishmael).
offspring(abraham, isaac).
offspring(isaac, esau).
offspring(isaac, jacob).

If for example the query

| ?- descendant(abraham, X).

is executed, Prolog's backtracking results in different descendants of Abraham being returned as successive instances of the variable X, i.e.

X = ishmael
X = isaac
X = esau
X = jacob


Node:Association Lists, Next:, Previous:Family Example, Up:Programming Examples

Association List Primitives

These predicates implement "association list" primitives. They use a binary tree representation. Thus the time complexity for these predicates is O(lg N), where N is the number of keys. These predicates also illustrate the use of compare/3 (see Term Compare) for case analysis.

The goal get_assoc(Key, Assoc, Value) is true when Key is identical to one of the keys in Assoc, and Value unifies with the associated value.

get_assoc(Key, t(K,V,L,R), Val) :-
        compare(Rel, Key, K),
        get_assoc(Rel, Key, V, L, R, Val).

get_assoc(=, _, Val, _, _, Val).
get_assoc(<, Key, _, Tree, _, Val) :-
        get_assoc(Key, Tree, Val).
get_assoc(>, Key, _, _, Tree, Val) :-
        get_assoc(Key, Tree, Val).


Node:Derivative, Next:, Previous:Association Lists, Up:Programming Examples

Differentiation

The goal d(E1, X, E2) is true if expression E2 is a possible form for the derivative of expression E1 with respect to X.

d(X, X, D) :- atomic(X), !, D = 1.
d(C, X, D) :- atomic(C), !, D = 0.
d(U+V, X, DU+DV) :- d(U, X, DU), d(V, X, DV).
d(U-V, X, DU-DV) :- d(U, X, DU), d(V, X, DV).
d(U*V, X, DU*V+U*DV) :- d(U, X, DU), d(V, X, DV).
d(U**N, X, N*U**N1*DU) :- integer(N), N1 is N-1, d(U, X, DU).
d(-U, X, -DU) :- d(U, X, DU).


Node:Use Of Meta, Next:, Previous:Derivative, Up:Programming Examples

Use of Meta-Logical Predicates

This example illustrates the use of the meta-logical predicates var/1, arg/3, and functor/3 (see Meta Logic). The procedure call variables(Term, L, []) instantiates variable L to a list of all the variable occurrences in the term Term. e.g.

| ?- variables(d(U*V, X, DU*V+U*DV), L, []).

L = [U,V,X,DU,V,U,DV]
variables(X, [X|L0], L) :- var(X), !, L = L0.
variables(T, L0, L) :-
%       nonvar(T),
        functor(T, _, A),
        variables(0, A, T, L0, L).

variables(A, A, _, L0, L) :- !, L = L0.
variables(A0, A, T, L0, L) :-
%       A0<A,
        A1 is A0+1,
        arg(A1, T, X),
        variables(X, L0, L1),
        variables(A1, A, T, L1, L).


Node:Use Of Term Exp, Next:, Previous:Use Of Meta, Up:Programming Examples

Use of Term Expansion

This example illustrates the use of user:term_expansion/[2,4] to augment the built-in predicate expand_term/2 which works as a filter on the input to compile and consult. The code below will allow the declaration :- wait f/3 as an alias for :- block f(-,?,?). Wait declarations were used in previous versions of SICStus Prolog.

Note the multifile declaration, which prevents this user:term_expansion/[2,4] clause from erasing any other clauses for the same predicate that might have been loaded.

:- op(1150, fx, [wait]).

:- multifile user:term_expansion/2.
user:term_expansion((:- wait F/N), (:- block Head)) :-
        functor(Head, F, N),
        wb_args(N, Head).

wb_args(0, _Head).
wb_args(1, Head) :- arg(1, Head, -).
wb_args(N, Head) :-
        N>1,
        arg(N, Head, ?),
        N1 is N-1,
        wb_args(N1, Head).


Node:Interpreter, Next:, Previous:Use Of Term Exp, Up:Programming Examples

Prolog in Prolog

This example shows how simple it is to write a Prolog interpreter in Prolog, and illustrates the use of a variable goal. In this mini-interpreter, goals and clauses are represented as ordinary Prolog data structures (i.e. terms). Terms representing clauses are specified using the predicate my_clause/1, e.g.

my_clause( (grandparent(X, Z) :- parent(X, Y), parent(Y, Z)) ).

A unit clause will be represented by a term such as

my_clause( (parent(john, mary) :- true) ).

The mini-interpreter consists of three clauses:

execute((P,Q)) :- !, execute(P), execute(Q).
execute(P) :- predicate_property(P, built_in), !, P.
execute(P) :- my_clause((P :- Q)), execute(Q).

The second clause enables the mini-interpreter to cope with calls to ordinary Prolog predicates, e.g. built-in predicates. The mini-interpreter needs to be extended to cope with the other control structures, i.e. !, (P;Q), (P->Q), (P->Q;R), (\+ P), and if(P,Q,R).


Node:Translate, Previous:Interpreter, Up:Programming Examples

Translating English Sentences into Logic Formulae

The following example of a definite clause grammar defines in a formal way the traditional mapping of simple English sentences into formulae of classical logic. By way of illustration, if the sentence

Every man that lives loves a woman.

is parsed as a sentence by the call

| ?- phrase(sentence(P), [every,man,that,lives,loves,a,woman]).

then P will get instantiated to

all(X):(man(X)&lives(X) => exists(Y):(woman(Y)&loves(X,Y)))

where :, & and => are infix operators defined by

:- op(900, xfx, =>).
:- op(800, xfy, &).
:- op(550, xfy, :). /* predefined */

The grammar follows:

sentence(P) --> noun_phrase(X, P1, P), verb_phrase(X, P1).

noun_phrase(X, P1, P) -->
        determiner(X, P2, P1, P), noun(X, P3), rel_clause(X, P3, P2).
noun_phrase(X, P, P) --> name(X).

verb_phrase(X, P) --> trans_verb(X, Y, P1), noun_phrase(Y, P1, P).
verb_phrase(X, P) --> intrans_verb(X, P).

rel_clause(X, P1, P1&P2) --> [that], verb_phrase(X, P2).
rel_clause(_, P, P) --> [].

determiner(X, P1, P2, all(X):(P1=>P2)) --> [every].
determiner(X, P1, P2, exists(X):(P1&P2)) --> [a].

noun(X, man(X)) --> [man].
noun(X, woman(X)) --> [woman].

name(john) --> [john].

trans_verb(X, Y, loves(X,Y)) --> [loves].
intrans_verb(X, lives(X)) --> [lives].


Node:The Prolog Library, Next:, Previous:Example Intro, Up:Top

The Prolog Library

The Prolog library comprises a number of packages which are thought to be useful in a number of applications. Note that the predicates in the Prolog library are not built-in predicates. One has to explicitly load each package to get access to its predicates. The following packages are provided:

arrays
provides an implementation of extendible arrays with logarithmic access time.
assoc
uses AVL trees to implement "association lists", i.e. extendible finite mappings from terms to terms.
atts
provides a means of associating with variables arbitrary attributes, i.e. named properties that can be used as storage locations as well as hooks into Prolog's unification.
heaps
implements binary heaps, the main application of which are priority queues.
lists
provides basic operations on lists.
terms
provides a number of operations on terms.
ordsets
defines operations on sets represented as lists with the elements ordered in Prolog standard order.
queues
defines operations on queues (FIFO stores of information).
random
provides a random number generator.
system
provides access to operating system services.
trees
uses binary trees to represent non-extendible arrays with logarithmic access time. The functionality is very similar to that of library(arrays), but library(trees) is slightly more efficient if the array does not need to be extendible.
ugraphs
provides an implementation of directed and undirected graphs with unlabeled edges.
wgraphs
provides an implementation of directed and undirected graphs where each edge has an integral weight.
sockets
provides an interface to system calls for manipulating sockets.
linda/client
linda/server
provides an implementation of the Linda concept for process communication.
bdb
provides an interface to Berkeley DB, for storage and retrieval of terms on disk files with user-defined multiple indexing.
clpb
provides constraint solving over Booleans.
clpq
clpr
provides constraint solving over Q (Rationals) or R (Reals).
clpfd
provides constraint solving over Finite (Integer) Domains
chr
provides Constraint Handling Rules
objects
provides the combination of the logic programming and the object-oriented programming paradigms.
tcltk
An interface to the Tcl/Tk language and toolkit.
gauge
is a profiling tool for Prolog programs with a graphical interface based on tcltk.
charsio
defines I/O predicates that read from, or write to, a list of character codes.
jasper
An interface to the Java language.
flinkage
is a utility program for generating glue code for the Foreign Language Interface when building statically linked runtime systems or development systems.
timeout
provides a way of running goals with an execution time limit.
xref
provides a cross reference producer for debugging and program analysis.
wcx_example
provides a sample implementation of a Wide Character Extension (WCX) box.

To load a library package Package, you will normally enter a query

| ?- use_module(library(Package)).

A library package normally consists of one or more hidden modules.

An alternative way of loading from the library is using the built-in predicate require/1 (see Read In). The index file INDEX.pl needed by require/1 can be created by the make_index program. This program is loaded as:

| ?- use_module(library(mkindex)).
make_index:make_library_index(+LibraryDirectory)

Creates a file INDEX.pl in LibraryDirectory. All *.pl files in the directory and all its subdirectories are scanned for module/2 declarations. From these declarations, the exported predicates are entered into the index.


Node:Arrays, Next:, Previous:The Prolog Library, Up:Top

Array Operations

This package provides an implementation of extendible arrays with logarithmic access time.

Beware: the atom $ is used to indicate an unset element, and the functor $ /4 is used to indicate a subtree. In general, array elements whose principal function symbol is $ will not work.

To load the package, enter the query

| ?- use_module(library(arrays)).
new_array(-Array)

Binds Array to a new empty array. Example:

| ?- new_array(A).

A = array($($,$,$,$),2) ?

yes

is_array(+Array)

Is true when Array actually is an array.

aref(+Index, +Array, ?Element)

Element is the element at position Index in Array. It fails if Array[Index] is undefined.

arefa(+Index, +Array, ?Element)

Is like aref/3 except that Element is a new array if Array[Index] is undefined. Example:

| ?- arefa(3, array($($,$,$,$),2), E).

E = array($($,$,$,$),2) ?

yes

arefl(+Index, +Array, ?Element)

Is as aref/3 except that Element is [] for undefined cells. Example:

| ?- arefl(3, array($($,$,$,$),2), E).

E = [] ?

yes

array_to_list(+Array, -List)

List is a list with the pairs Index-Element of all the elements of Array. Example:

| ?- array_to_list(array($(a,b,c,d),2), List).

List = [0-a,1-b,2-c,3-d] ?

yes

aset(+Index, +Array, +Element, -NewArray)

NewArray is the result of setting Array[Index] to Element. Example:

| ?- aset(3,array($($,$,$,$),2), a, Newarr).

Newarr = array($($,$,$,a),2) ?

yes


Node:Assoc, Next:, Previous:Arrays, Up:Top

Association Lists

In this package, finite mappings ("association lists") are represented by AVL trees, i.e. they are subject to the Adelson-Velskii-Landis balance criterion:

A tree is balanced iff for every node the heights of its two subtrees differ by at most 1.

The empty tree is represented as t. A tree with key K, value V, and left and right subtrees L and R is represented as t(K,V,|R|-|L|,L,R), where |T| denotes the height of T.

The advantage of this representation is that lookup, insertion and deletion all become--in the worst case--O(log n) operations.

The algorithms are from [Wirth 76], section 4.4.6-4.4.8.

To load the package, enter the query

| ?- use_module(library(assoc)).
empty_assoc(?Assoc)

Assoc is an empty AVL tree.

assoc_to_list(+Assoc, ?List)

List is a list of Key-Value pairs in ascending order with no duplicate Keys specifying the same finite function as the association tree Assoc. Use this to convert an association tree to a list.

is_assoc(+Assoc)

Assoc is a (proper) AVL tree. It checks both that the keys are in ascending order and that Assoc is properly balanced.

min_assoc(+Assoc, ?Key, ?Val)

Key is the smallest key in Assoc and Val is its value.

max_assoc(+Assoc, ?Key, ?Val)

Key is the greatest key in Assoc and Val is its value.

gen_assoc(?Key, +Assoc, ?Value)

Key is associated with Value in the association tree Assoc. Can be used to enumerate all Values by ascending Keys.

get_assoc(+Key, +Assoc, ?Value)

Key is identical (==) to one of the keys in the association tree Assoc, and Value unifies with the associated value.

get_assoc(+Key, +OldAssoc, ?OldValue, ?NewAssoc, ?NewValue)

OldAssoc and NewAssoc are association trees of the same shape having the same elements except that the value for Key in OldAssoc is OldValue and the value for Key in NewAssoc is NewValue.

get_next_assoc(+Key, +Assoc, ?Knext, ?Vnext)

Knext and Vnext is the next key and associated value after Key in Assoc.

get_prev_assoc(+Key, +Assoc, ?Kprev, ?Vprev)

Kprev and Vprev is the previous key and associated value after Key in Assoc.

list_to_assoc(+List, ?Assoc)

List is a proper list of Key-Value pairs (in any order) and Assoc is an association tree specifying the same finite function from Keys to Values.

ord_list_to_assoc(+List, ?Assoc)

List is a proper list of Key-Value pairs (keysorted) and Assoc is an association tree specifying the same finite function from Keys to Values.

map_assoc(:Pred, ?Assoc)

Assoc is an association tree, and for each Key, if Key is associated with Value in Assoc, Pred(Value) is true.

map_assoc(:Pred, ?OldAssoc, ?NewAssoc)

OldAssoc and NewAssoc are association trees of the same shape, and for each Key, if Key is associated with Old in OldAssoc and with New in NewAssoc, Pred(Old,New) is true.

put_assoc(+Key, +OldAssoc, +Val, ?NewAssoc)

OldAssoc and NewAssoc define the same finite function, except that NewAssoc associates Val with Key. OldAssoc need not have associated any value at all with Key.

del_assoc(+Key, +OldAssoc, ?Val, ?NewAssoc)

OldAssoc and NewAssoc define the same finite function except that OldAssoc associates Key with Val and NewAssoc doesn't associate Key with any value.

del_min_assoc(+OldAssoc, ?Key, ?Val, ?NewAssoc)

OldAssoc and NewAssoc define the same finite function except that OldAssoc associates Key with Val and NewAssoc doesn't associate Key with any value and Key precedes all other keys in OldAssoc.

del_max_assoc(+OldAssoc, ?Key, ?Val, -NewAssoc)

OldAssoc and NewAssoc define the same finite function except that OldAssoc associates Key with Val and NewAssoc doesn't associate Key with any value and Key is preceded by all other keys in OldAssoc.


Node:Attributes, Next:, Previous:Assoc, Up:Top

Attributed Variables

This package implements attributed variables. It provides a means of associating with variables arbitrary attributes, i.e. named properties that can be used as storage locations as well as to extend the default unification algorithm when such variables are unified with other terms or with each other. This facility was primarily designed as a clean interface between Prolog and constraint solvers, but has a number of other uses as well. The basic idea is due to Christian Holzbaur and he was actively involved in the final design. For background material, see the dissertation [Holzbaur 90].

To load the package, enter the query

| ?- use_module(library(atts)).

The package provides a means to declare and access named attributes of variables. The attributes are compound terms whose arguments are the actual attribute values. The attribute names are private to the module in which they are defined. They are defined with a declaration

:- attribute AttributeSpec, ..., AttributeSpec.

where each AttributeSpec has the form (Name/Arity). There must be at most one such declaration in a module Module.

Having declared some attribute names, these attributes can now be added, updated and deleted from unbound variables. For each declared attribute name, any variable can have at most one such attribute (initially it has none).

The declaration causes the following two access predicates to become defined by means of the user:goal_expansion/3 mechanism. They take a variable and an AccessSpec as arguments where an AccessSpec is either +(Attribute), -(Attribute), or a list of such. The + prefix may be dropped for convenience. The meaning of the +/- prefix is documented below:


Module:get_atts(-Var, ?AccessSpec)
Gets the attributes of Var according to AccessSpec. If AccessSpec is unbound, it will be bound to a list of all set attributes of Var. Non-variable terms cause a type error to be raised. The prefixes in the AccessSpec have the following meaning:
+(Attribute)
The corresponding actual attribute must be present and is unified with Attribute.
-(Attribute)
The corresponding actual attribute must be absent. The arguments of Attribute are ignored, only the name and arity are relevant.

Module:put_atts(-Var, +AccessSpec)
Sets the attributes of Var according to AccessSpec. Non-variable terms cause a type error to be raised. The effects of put_atts/2 are undone on backtracking.
+(Attribute)
The corresponding actual attribute is set to Attribute. If the actual attribute was already present, it is simply replaced.
-(Attribute)
The corresponding actual attribute is removed. If the actual attribute was already absent, nothing happens.

A module that contains an attribute declaration has an opportunity to extend the default unification algorithm by defining the following predicate:


Module:verify_attributes(-Var, +Value, -Goals) [Hook]
This predicate is called whenever a variable Var that might have attributes in Module is about to be bound to Value (it might have none). The unification resumes after the call to verify_attributes/3. Value is a non-variable term, or another attributed variable. Var might have no attributes present in Module; the unification extension mechanism is not sophisticated enough to filter out exactly the variables that are relevant for Module.

verify_attributes/3 is called before Var has actually been bound to Value. If it fails, the unification is deemed to have failed. It may succeed non-deterministically, in which case the unification might backtrack to give another answer. It is expected to return, in Goals, a list of goals to be called after Var has been bound to Value.

verify_attributes/3 may invoke arbitrary Prolog goals, but Var should not be bound by it. Binding Var will result in undefined behavior.

If Value is a non-variable term, verify_attributes/3 will typically inspect the attributes of Var and check that they are compatible with Value and fail otherwise. If Value is another attributed variable, verify_attributes/3 will typically copy the attributes of Var over to Value, or merge them with Value's, in preparation for Var to be bound to Value. In either case, verify_attributes/3 may determine Var's current attributes by calling get_atts(Var,List) with an unbound List.

An important use for attributed variables is in implementing coroutining facilities as an alternative or complement to the built-in coroutining mechanisms. In this context it might be useful to be able to interpret some of the attributes of a variable as a goal that is blocked on that variable. Certain built-in predicates (frozen/2, call_residue/2) and the Prolog top level need to access blocked goals, and so need a means of getting the goal interpretation of attributed variables by calling:


Module:attribute_goal(-Var, -Goal) [Hook]
This predicate is called in each module that contains an attribute declaration, when an interpretation of the attributes as a goal is needed. It should unify Goal with the interpretation, or merely fail if no such interpretation is available.

An important use for attributed variables is to provide an interface to constraint solvers. An important function for a constraint solver in the constraint logic programming paradigm is to be able to perform projection of the residual constraints onto the variables that occurred in the top-level query. A module that contains an attribute declaration has an opportunity to perform such projection of its residual constraints by defining the following predicate:


Module:project_attributes(+QueryVars, +AttrVars) [Hook]
This predicate is called by the Prolog top level and by the built-in predicate call_residue/2 in each module that contains an attribute declaration. QueryVars is the list of variables occurring in the query, or in terms bound to such variables, and AttrVars is a list of possibly attributed variables created during the execution of the query. The two lists of variables may or may not be disjoint.

If the attributes on AttrVars can be interpreted as constraints, this predicate will typically "project" those constraints onto the relevant QueryVars. Ideally, the residual constraints will be expressed entirely in terms of the QueryVars, treating all other variables as existentially quantified. Operationally, project_attributes/2 must remove all attributes from AttrVars, and add transformed attributes representing the projected constraints to some of the QueryVars.

Projection has the following effect on the Prolog top level. When the top level query has succeeded, project_attributes/2 is called first. The top level then prints the answer substition and residual constraints. While doing so, it searches for attributed variables created during the execution of the query. For each such variable, it calls attribute_goal/2 to get a printable representation of the constraint encoded by the attribute. Thus, project_attributes/2 is a mechanism for controlling how the residual constraints should be displayed at top level.

Similarly during the execution of call_residue(Goal,Residue), when Goal has succeeded, project_attributes/2 is called. After that, all attributed variables created during the execution of Goal are located. For each such variable, attribute_goal/2 produces a term representing the constraint encoded by the attribute, and Residue is unified with the list of all such terms.

The exact definition of project_attributes/2 is constraint system dependent, but see Projection for details about projection in clp(Q,R).

In the following example we sketch the implementation of a finite domain "solver". Note that an industrial strength solver would have to provide a wider range of functionality and that it quite likely would utilize a more efficient representation for the domains proper. The module exports a single predicate domain(-Var,?Domain) which associates Domain (a list of terms) with Var. A variable can be queried for its domain by leaving Domain unbound.

We do not present here a definition for project_attributes/2. Projecting finite domain constraints happens to be difficult.

:- module(domain, [domain/2]).

:- use_module(library(atts)).
:- use_module(library(ordsets), [
        ord_intersection/3,
        ord_intersect/2,
        list_to_ord_set/2
   ]).

:- attribute dom/1.

verify_attributes(Var, Other, Goals) :-
        get_atts(Var, dom(Da)), !,          % are we involved?
        (   var(Other) ->                   % must be attributed then
            (   get_atts(Other, dom(Db)) -> %   has a domain?
                ord_intersection(Da, Db, Dc),
                Dc = [El|Els],              % at least one element
                (   Els = [] ->             % exactly one element
                    Goals = [Other=El]      % implied binding
                ;   Goals = [],
                    put_atts(Other, dom(Dc))% rescue intersection
                )
            ;   Goals = [],
                put_atts(Other, dom(Da))    % rescue the domain
            )
        ;   Goals = [],
            ord_intersect([Other], Da)      % value in domain?
        ).
verify_attributes(_, _, []).                % unification triggered
                                            % because of attributes
                                            % in other modules

attribute_goal(Var, domain(Var,Dom)) :-     % interpretation as goal
        get_atts(Var, dom(Dom)).

domain(X, Dom) :-
        var(Dom), !,
        get_atts(X, dom(Dom)).
domain(X, List) :-
        list_to_ord_set(List, Set),
        Set = [El|Els],                     % at least one element
        (   Els = [] ->                     % exactly one element
            X = El                          % implied binding
        ;   put_atts(Fresh, dom(Set)),
            X = Fresh                       % may call
                                            % verify_attributes/3
        ).

Note that the "implied binding" Other=El was deferred until after the completion of verify_attribute/3. Otherwise, there might be a danger of recursively invoke verify_attribute/3, which might bind Var, which is not allowed inside the scope of verify_attribute/3. Deferring unifications into the third argument of verify_attribute/3 effectively serializes th calls to verify_attribute/3.

Assuming that the code resides in the file domain.pl, we can use it via:

| ?- use_module(domain).

Let's test it:

| ?- domain(X,[5,6,7,1]), domain(Y,[3,4,5,6]), domain(Z,[1,6,7,8]).

domain(X,[1,5,6,7]),
domain(Y,[3,4,5,6]),
domain(Z,[1,6,7,8]) ?

yes
| ?- domain(X,[5,6,7,1]), domain(Y,[3,4,5,6]), domain(Z,[1,6,7,8]),
     X=Y.

Y = X,
domain(X,[5,6]),
domain(Z,[1,6,7,8]) ?

yes
| ?- domain(X,[5,6,7,1]), domain(Y,[3,4,5,6]), domain(Z,[1,6,7,8]),
     X=Y, Y=Z.

X = 6,
Y = 6,
Z = 6

To demonstrate the use of the Goals argument of verify_attributes/3, we give an implementation of freeze/2. We have to name it myfreeze/2 in order to avoid a name clash with the built-in predicate of the same name.

:- module(myfreeze, [myfreeze/2]).

:- use_module(library(atts)).

:- attribute frozen/1.

verify_attributes(Var, Other, Goals) :-
        get_atts(Var, frozen(Fa)), !,       % are we involved?
        (   var(Other) ->                   % must be attributed then
            (   get_atts(Other, frozen(Fb)) % has a pending goal?
            ->  put_atts(Other, frozen((Fa,Fb))) % rescue conjunction
            ;   put_atts(Other, frozen(Fa)) % rescue the pending goal
            ),
            Goals = []
        ;   Goals = [Fa]
        ).
verify_attributes(_, _, []).

attribute_goal(Var, Goal) :-                % interpretation as goal
        get_atts(Var, frozen(Goal)).

myfreeze(X, Goal) :-
        put_atts(Fresh, frozen(Goal)),
        Fresh = X.

Assuming that this code lives in file myfreeze.pl, we would use it via:

| ?- use_module(myfreeze).
| ?- myfreeze(X,print(bound(x,X))), X=2.

bound(x,2)                      % side effect
X = 2                           % bindings

The two solvers even work together:

| ?- myfreeze(X,print(bound(x,X))), domain(X,[1,2,3]),
     domain(Y,[2,10]), X=Y.

bound(x,2)                      % side effect
X = 2,                          % bindings
Y = 2

The two example solvers interact via bindings to shared attributed variables only. More complicated interactions are likely to be found in more sophisticated solvers. The corresponding verify_attributes/3 predicates would typically refer to the attributes from other known solvers/modules via the module prefix in Module:get_atts/2.


Node:Heaps, Next:, Previous:Attributes, Up:Top

Heap Operations

A binary heap is a tree with keys and associated values that satisfies the heap condition: the key of every node is greater than or equal to the key of its parent, if it has one. The main application of binary heaps are priority queues. To load the package, enter the query

| ?- use_module(library(heaps)).

add_to_heap(+OldHeap, +Key, +Datum, ?NewHeap)

Inserts the new Key-Datum pair into the current heap OldHeap producing the new heap NewHeap. The insertion is not stable, that is, if you insert several pairs with the same Key it is not defined which of them will come out first, and it is possible for any of them to come out first depending on the history of the heap. Example:

| ?- add_to_heap(t(0,[],t),3,678,N).

N = t(1,[],t(3,678,t,t)) ?

yes

get_from_heap(+OldHeap, ?Key, ?Datum, ?NewHeap)

Returns the Key-Datum pair in OldHeap with the smallest Key, and also a NewHeap which is the OldHeap with that pair deleted. Example:

get_from_heap(t(1,[],t(1,543,t,t)),K,D,N).

D = 543,
K = 1,
N = t(0,[1],t) ?

yes

empty_heap(?Heap)

is true when Heap is the empty heap.

heap_size(+Heap, ?Size)

Size is the number of elements in the heap Heap.

heap_to_list(+Heap, -List)

Returns the current set of Key-Datum pairs in the Heap as a keysorted List.

is_heap(+Heap)

is true when Heap is a valid heap.

list_to_heap(+List, -Heap)

Takes a list List of Key-Datum pairs and forms them into a heap Heap. Example:

| ?- list_to_heap([1-34,2-345,5-678],H).

H = t(3,[],t(1,34,t(2,345,t,t),t(5,678,t,t))) ?

yes

min_of_heap(+Heap, ?Key, ?Datum)

Returns the Key-Datum pair at the top of the heap Heap without removing it. Fails if the heap is empty.

min_of_heap(+Heap, ?Key1, ?Datum1, ?Key2, ?Datum2)

Returns the smallest (Key1-Datum1) and second smallest (Key2-Datum2) pairs in the Heap, without deleting them. It fails if the heap does not have at least two elements.

delete_from_heap(+OldHeap, +Key, ?Datum, ?NewHeap)

deletes a single Key-Datum pair in OldHeap producing NewHeap. This is useful if you want to e.g. change the priority of Datum. Beware: this operation needs to search the whole heap in the worst case.


Node:Lists, Next:, Previous:Heaps, Up:Top

List Operations

This package defines operations on lists. Lists are a very basic data structure, but nevertheless certain very frequent operations are provided in this package.

To load the package, enter the query

| ?- use_module(library(lists)).
append(?Prefix, ?Suffix, ?Combined)

Combined is the combined list of the elements in Prefix followed by the elements in Suffix. It can be used to form Combined or it can be used to find Prefix and/or Suffix from a given Combined.

delete(+List, +Element, ?Residue)

Residue is the result of removing all identical occurrences of Element in List.

is_list(+List)

List is a proper list.

last(?List, ?Last)

Last is the last element in List. Example:

| ?- last([x,y,z], Z).

Z = z ?

yes

max_list(+ListOfNumbers, ?Max)

Max is the largest of the elements in ListOfNumbers.

member(?Element, ?List)

Element is a member of List. It may be used to test for membership in a list, but it can also be used to enumerate all the elements in List. Example:

| ?- member(X, [a,b,c]).

X = a ? ;

X = b ? ;

X = c ?

yes

memberchk(+Element, +List)

Element is a member of List, but memberchk/2 only succeeds once and can therefore not be used to enumerate the elements in List. Example:

| ?- memberchk(X, [a,b,c]).

X = a ? ;

no

min_list(+ListOfNumbers, ?Min)

Min is the smallest of the numbers in the list ListOfNumbers.

nextto(?X, ?Y, ?List)

X and Y appears side-by-side in List. Example:

| ?- nextto(X, Y, [1,2,3]).

X = 1,
Y = 2 ? ;

X = 2,
Y = 3 ? ;

no

no_doubles(?List)

List contains no duplicated elements. This is true when dif(X, Y) holds for all pairs of members X and Y of the list.

non_member(?Element, ?List)

Element does not occur in List. This is true when dif(Element, Y) holds for all members Y of the list.

nth(?N, ?List, ?Element)

Element is the Nth element of List. The first element is number 1. Example:

| ?- nth(N, [a,b,c,d,e,f,g,h,i], f).

N = 6 ?

yes

nth(?N, ?List, ?Element, ?Rest)

Element is in position N in the List and Rest is all elements in List except Element.

nth0(?N, ?List, ?Element)

Element is the Nth element of List, counting the first element as 0.

nth0(?N, ?List, ?Element, ?Rest)

Element is the Nth element of List, counting the first element as 0. Rest is all the other elements in List. Example:

| ?- nth0(N, [a,b,c,d,e,f,g,h,i,j], f, R).

N = 5,
R = [a,b,c,d,e,g,h,i,j] ?

yes

permutation(?List, ?Perm)

Perm is a permutation of List.

prefix(?Prefix, ?List)

Prefix is a prefix of List. Example:

| ?- prefix([1,2,3], [1,2,3,4,5,6]).

yes

remove_duplicates(+List, ?Pruned)

Pruned is the result of removing all identical duplicate elements in List. Example:

| ?- remove_duplicates([1,2,3,2,3,1], P).

P = [1,2,3] ? ;

no

reverse(?List, ?Reversed)

Reversed has the same elements as List but in a reversed order.

same_length(?List1, ?List2)

List1 and List2 have the same number of elements.

same_length(?List1, ?List2, ?Length)

List1 and List2 have the same number of elements and that number is Length. Example:

| ?- same_length([1,2,3], [9,8,7], N).

N = 3 ? ;

no

select(?Element, ?List, ?List2)

The result of removing an occurrence of Element in List is List2.

sublist(?Sub, ?List)

Sub contains some of the elements of List, in the same order.

substitute(+X, +Xlist, +Y, ?Ylist)

Xlist and Ylist are equal except for replacing identical occurrences of X by Y. Example:

| ?- substitute(1, [1,2,3,4], 5, X).

X = [5,2,3,4] ?

yes

sum_list(+ListOfNumbers, ?Sum)

Sum is the result of adding the ListOfNumbers together.

suffix(?Suffix, ?List)

Suffix is a suffix of List.


Node:Term Utilities, Next:, Previous:Lists, Up:Top

Term Utilities

This package defines operations on terms for subsumption checking, "anti-unification", unification with occurs-check, testing acyclicity, and getting the variables.

To load the package, enter the query

| ?- use_module(library(terms)).
subsumes_chk(?General, ?Specific)

Specific is an instance of General, i.e. if there is a substitution that leaves Specific unchanged and makes General identical to Specific. It doesn't bind any variables.

subsumes_chk(f(X), f(a)).

true

| ?- subsumes_chk(f(a), f(X)).

no

| ?- subsumes_chk(A-A, B-C).

no

| ?- subsumes_chk(A-B, C-C).

true

subsumes(?General, ?Specific)

Specific is an instance of General. It will bind variables in General (but not those in Specific) so that General becomes identical to Specific.

variant(?Term, ?Variant)

Term and Variant are identical modulo renaming of variables, provided Term and Variant have no variables in common.

term_subsumer(?Term1, ?Term2, ?General)

General is the most specific term that generalizes Term1 and Term2. This process is sometimes called anti-unification, as it is the dual of unification.

| ?- term_subsumer(f(g(1,h(_))), f(g(_,h(1))), T).

T = f(g(_B,h(_A)))

| ?- term_subsumer(f(1+2,2+1), f(3+4,4+3), T).

T = f(_A+_B,_B+_A)


term_hash(?Term, ?Hash)
term_hash(?Term, +Depth, +Range, ?Hash)

If Term is instantiated up to the given Depth, an integer hash value in the range [0,Range) as a function of Term is unified with Hash. Otherwise, the goal just succeeds, leaving Hash uninstantiated.

If Term contains floats or integers outside the range [-33554432,33554431], the hash value will be platform dependent. Otherwise, the hash value will be identical across runs and platforms.

The depth of a term is defined as follows: the (principal functor of) the term itself has depth 1, and an argument of a term with depth i has depth i+1.

Depth should be an integer >= -1. If Depth = -1 (the default), Term must be ground, and all subterms of Term are relevant in computing Hash. Otherwise, only the subterms up to depth Depth of Term are used in the computation.

Range should be an integer >= 1. The default will give hash values in a range appropriate for all platforms.

| ?- term_hash([a,b,_], 3, 4, H).

H = 2

| ?- term_hash([a,b,_], 4, 4, H).

true

| ?- term_hash(f(a,f(b,f(_,[]))), 2, 4, H).

H = 2

term_hash/[2,4] is provided primarily as a tool for the construction of sophisticated Prolog clause access schemes. Its intended use is to generate hash values for terms that will be used with first argument clause indexing, yielding compact and efficient multi-argument or deep argument indexing.

term_variables(?Term, ?Variables)

Variables is the set of variables occurring in Term.

acyclic_term(?X)

True if X is finite (acyclic). Runs in linear time.

cyclic_term(?X)

True if X is infinite (cyclic). Runs in linear time.


Node:Ordsets, Next:, Previous:Term Utilities, Up:Top

Ordered Set Operations

This package defines operations on ordered sets. Ordered sets are sets represented as lists with the elements ordered in a standard order. The ordering is defined by the @< family of term comparison predicates and it is the ordering produced by the built-in predicate sort/2 (see Term Compare).

To load the package, enter the query

| ?- use_module(library(ordsets)).
is_ordset(+Set)

Set is an ordered set.

list_to_ord_set(+List, ?Set)

Set is the ordered representation of the set denoted by the unordered representation List. Example:

| ?- list_to_ord_set([p,r,o,l,o,g], P).

P = [g,l,o,p,r] ?

yes


ord_add_element(+Set1, +Element ?Set2)

Set2 is Set1 with Element inserted in it, preserving the order. Example:

| ?- ord_add_element([a,c,d,e,f], b, N).

N = [a,b,c,d,e,f] ?

yes

ord_del_element(+Set1, +Element, ?Set2)

Set2 is like Set1 but with Element removed.

ord_disjoint(+Set1, +Set2)

The two ordered sets have no elements in common.

ord_intersect(+Set1, +Set2)

The two ordered sets have at least one element in common.

ord_intersection(+Set1, +Set2, ?Intersect)

Intersect is the ordered set representation of the intersection between Set1 and Set2.

ord_intersection(+Set1, +Set2, ?Intersect, ?Diff)

Intersect is the intersection between Set1 and Set2, and Diff is the difference between Set2 and Set1.

ord_intersection(+Sets, ?Intersection)

Intersection is the ordered set representation of the intersection of all the sets in Sets. Example:

| ?- ord_intersection([[1,2,3],[2,3,4],[3,4,5]], I).

I = [3] ?

yes


ord_member(+Elt, +Set)

is true when Elt is a member of Set.

ord_seteq(+Set1, +Set2)

Is true when the two arguments represent the same set. Since they are assumed to be ordered representations, they must be identical.

ord_setproduct(+Set1, +Set2, ?SetProduct)

SetProduct is the Cartesian Product of the two Sets. The product is represented as pairs: Elem1-Elem2 where Elem1 is an element from Set1 and Elem2 is an element from Set2. Example

| ?- ord_setproduct([1,2,3], [4,5,6], P).

P = [1-4,1-5,1-6,2-4,2-5,2-6,3-4,3-5,3-6] ?

yes

ord_subset(+Set1, +Set2)

Every element of the ordered set Set1 appears in the ordered set Set2.

ord_subtract(+Set1, +Set2, ?Difference)

Difference contains all and only the elements of Set1 which are not also in Set2. Example:

| ?- ord_subtract([1,2,3,4], [3,4,5,6], S).

S = [1,2] ?

yes

ord_symdiff(+Set1, +Set2, ?Difference)

Difference is the symmetric difference of Set1 and Set2. Example:

| ?- ord_symdiff([1,2,3,4], [3,4,5,6], D).

D = [1,2,5,6] ?

yes

ord_union(+Set1, +Set2, ?Union)

Union is the union of Set1 and Set2.

ord_union(+Set1, +Set2, ?Union, ?New)

Union is the union of Set1 and Set2, and New is the difference between Set2 and Set1. This is useful if you are accumulating members of a set and you want to process new elements as they are added to the set.

ord_union(+Sets, ?Union)

Union is the union of all the sets in Sets. Example:

| ?- ord_union([[1,2,3],[2,3,4],[3,4,5]], U).

U = [1,2,3,4,5] ?

yes


Node:Queues, Next:, Previous:Ordsets, Up:Top

Queue Operations

A queue is a first-in, first-out store of information. This implementation of queues uses difference-lists, the head of the difference-list represents the beginning of the queue and the tail represents the end of the queue. The members of the difference-list are the elements in the queue. The first argument in the queue-representation is the number of elements in the queue in unary representation.

Thus, a queue with n elements is represented as follows:

q(s(...s(0)...), [X1,...,Xn,Y1,...,Ym], [Y1,...,Ym])

where n is the length of the queue and X1...Xn are the elements of the queue.

To load the package, enter the query

| ?- use_module(library(queues)).
empty_queue(?Queue)

Is true if Queue has no elements.

is_queue(+Queue)

is true when Queue is a valid queue.

queue(?X, ?Queue)

Is true if Queue has one element and that is X.

queue_head(?Head, ?Queue1, ?Queue2)

Queue1 and Queue2 are the same queues except that Queue2 has Head inserted in the front. It can be used to enqueue the first element in Queue2. Example:

| ?- queue_head(Head, Nq,
                q(s(s(s(s(0)))),[1,2,3,4|R],R)).

Head = 1,
Nq = q(s(s(s(0))),[2,3,4|_193],_193),
R = _193 ?

yes

queue_head_list(+HeadList, ?Queue1, ?Queue2)

Queue1 and Queue2 have the same elements except that Queue2 has HeadList inserted in the front.

queue_last(?Last, ?Queue1, ?Queue2)

Queue2 is like Queue1 but have Last as the last element in the queue.

queue_last_list(+LastList, ?Queue1, ?Queue2)

Queue1 and Queue2 are the same queues except that Queue2 has the list of elements LastList last in the queue. Example:

| ?- queue_last_list([5,6], q(s(s(0)))), [1,2|R], R), NQ).

NQ = q(s(s(s(s(0)))))),[1,2,5,6|_360],_360),
R = [5,6|_360] ?

yes

list_queue(+List, ?Queue)

Queue is the queue representation of the elements in List. Example:

| ?- list_queue([1,2,3,4], Q).

Q = q(s(s(s(s(0)))),[1,2,3,4|_138],_138) ?

yes
| ?-

queue_length(+Queue, ?Length)

Length is the number of elements in Queue. Example:

| ?- queue_length(q(s(s(s(s(s(0))))),[a,b,c,d,e|R],R), L).

L = 5,
R = _155 ?

yes


Node:Random, Next:, Previous:Queues, Up:Top

Random Number Generator

This package provides a random number generator. To load the package, enter the query

| ?- use_module(library(random)).
random(-Number)

Binds Number to a random float in the interval [0.0, 1.0). Note that 1.0 will never be generated.

random(+Lower, +Upper, -Number)

Binds Number to a random integer in the interval [Lower,Upper) if Lower and Upper are integers. Otherwise Number is bound to a random float between Lower and Upper. Upper will never be generated.

randseq(+K, +N, -RandomSeq)

Generates a unordered set of K unique integers, chosen randomly in the range 1..N. RandomSeq is not returned in any particular order.

randset(+K, +N, -RandomSet)

Generates an ordered set of K unique integers, chosen randomly in the range 1..N. The set is returned in standard order.

getrand(?State)

Tries to unify State with the term rand(X,Y,Z) where X, Y, and Z are integers describing the state of the random generator.

setrand(rand(+X,+Y,+Z))

Sets the state of the random generator. X, Y, and Z must be integers in the ranges [1,30269), [1,30307), and [1,30323), respectively.


Node:System Utilities, Next:, Previous:Random, Up:Top

Operating System Utilities

This package contains utilities for invoking services from the operating system. To load the package, enter the query

| ?- use_module(library(system)).

Certain predicates described below take names of files or directories as arguments. These must be given as atoms, and the predicates below will not call absolute_file_name/2 on them.

Some predicates are described as invoking the default shell. Specifically this means invoking /bin/sh on UNIX platforms. On MSDOS, Windows and OS/2, the command interpreter given by the environment variable COMSPEC is invoked.

datime(-Datime)
Datime is a timestamp of the form datime(Year,Month,Day,Hour,Min,Sec) containing the current date and time. All fields are integers.
delete_file(+FileName,+Options)
FileName is the name of an existing file or directory. Options is a list of options. Possible options are directory, recursive or ignore. If FileName is not a directory it is deleted, otherwise if the option directory is specified but not recursive, the directory will be deleted if it is empty. If recursive is specified and FileName is a directory, the directory and all its subdirectories and files will be deleted. If the operation fails, an exception is raised unless the ignore option is specified.
delete_file(+FileName)

Equivalent to delete_file(FileName,[recursive]).

directory_files(+Directory,-FileList)

FileList is the list of entries (files, directories, etc.) in Directory.

make_directory(+DirectoryName)

Makes a new directory.

environ(?Var, ?Value)

Var is the name of an environment variable, and Value is its value. Both are atoms. Can be used to enumerate all current environment variables.

exec(+Command, [+Stdin,+Stdout,+Stderr], -Pid)

Passes Command to a new default shell process for execution. The standard I/O streams of the new process are connected according to what is specified by the terms +Stdin, +Stdout, and +Stderr respectively. Possible values are:

null
Connected to /dev/null or equivalent.
std
The standard stream is shared with the calling process. Note that the standard stream may not be referring to a console if the calling process is windowed. To portably print the output from the subprocess on the Prolog console, pipe/1 must be used and the program must explicitly read the pipe and write to the console. Similarly for the input to the subprocess.
pipe(-Stream)
A pipe is created which connects the Prolog stream Stream to the standard stream of the new process. It must be closed using close/1; it is not closed automatically when the process dies.

Pid is the process identifier of the new process.

On UNIX, the subprocess will be detached provided none of its standard streams is specified as std. This means it will not receive an interruption signal as a result of ^C being typed.

file_exists(+FileName)
FileName is the name of an existing file or directory.
file_exists(+FileName, +Permissions)
FileName is the name of an existing file or directory which can be accessed according to Permissions. Permissions is an atom, an integer (see access(2)), or a list of atoms and/or integers. The atoms must be drawn from the list [read,write,search,exists].
file_property(+FileName, ?Property)
FileName has the property Property. The possible properties are:
type(Type)
Type is one of regular, directory, fifo, symlink, socket or unknown.
size(Size)
Size is the size of FileName.
mod_time(ModTime)
ModTime is the time of the last modification of FileName.

If Property is uninstantiated, the predicate will enumerate the properties on backtracking.

host_id(-HID)
HID is the unique identifier, represented by an atom, of the host executing the current SICStus Prolog process.
host_name(-HostName)
HostName is the standard host name of the host executing the current SICStus Prolog process.
pid(-PID)
PID is the identifier of the current SICStus Prolog process.
kill(+Pid, +Signal)

Sends the signal Signal to process Pid.

mktemp(+Template, -FileName)

Interface to the UNIX function mktemp(3). A unique file name is created and unified with FileName. Template should contain a file name with six trailing Xs. The unique file name is that template with the six Xs replaced by a character string.

popen(+Command, +Mode, ?Stream)

Interface to the UNIX function popen(3). Passes Command to a new default shell process for execution. Mode may be either read or write. In the former case the output from the process is piped to Stream. In the latter case the input to the process is piped from Stream. Stream may be read/written using the ordinary StreamIO predicates. It must be closed using close/1; it is not closed automatically when the process dies.

rename_file(+OldName, +NewName)

OldName is the name of an existing file or directory, which will be renamed to NewName. If the operation fails, an exception is raised.

shell

Starts a new interactive shell named by the environment variable SHELL. The control is returned to Prolog upon termination of the shell process.

shell(+Command)

Passes Command to a new shell named by the environment variable SHELL for execution. Succeeds if the return status value is 0.

On MSDOS, Windows or OS/2, if SHELL is defined it is expected to name a UNIX like shell which will be invoked with the argument -c Command. If SHELL is undefined, the shell named by COMSPEC will be invoked with the argument /C Command.

shell(+Command, -Status)

Passes Command to a new shell named by the environment variable SHELL for execution. The status value is returned in Status. See also shell/1 above.

sleep(+Seconds)

Puts the SICStus Prolog process asleep for Second seconds, where Seconds may be an integer or a float. On UNIX, the usleep function will be used if Seconds is less than one, and sleep otherwise. On MSDOS, Windows or OS/2, the Sleep function will be used.

system

Starts a new interactive default shell process. The control is returned to Prolog upon termination of the shell process.

system(+Command)

Passes Command to a new default shell process for execution. Succeeds if the return status value is 0.

system(+Command, -Status)

Passes Command to a new default shell process for execution. The status value is returned in Status.

tmpnam(-FileName)

Interface to the ANSI C function tmpnam(3). A unique file name is created and unified with FileName.

wait(+Pid, -Status)

Waits for the child process Pid to terminate. The exit status is returned in Status. The function is similar to that of the UNIX function waitpid(3).

working_directory(?OldDirectory, ?NewDirectory)
OldDirectory is the current working directory, and the working directory is set to NewDirectory. In particular, the goal working_directory(Dir,Dir) unifies Dir with the current working directory without changing anything.


Node:Trees, Next:, Previous:System Utilities, Up:Top

Updatable Binary Trees

This package uses binary trees to represent arrays of N elements where N is fixed, unlike library(arrays). To load the package, enter the query

| ?- use_module(library(trees)).

Binary trees have the following representation: t denotes the empty tree, and t(Label,Left,Right) denotes the binary tree with label Label and children Left and Right.

gen_label(?Index, +Tree, ?Label)

Label labels the Index-th element in the Tree. Can be used to enumerate all Labels by ascending Index. Use get_label/3 instead if Index is instantiated.

get_label(+Index, +Tree, ?Label)

Label labels the Index-th element in the Tree.

list_to_tree(+List, -Tree)

Constructs a binary Tree from List where get_label(K,Tree,Lab) iff Lab is the Kth element of List.

map_tree(:Pred, ?OldTree, ?NewTree)

OldTree and NewTree are binary trees of the same shape and Pred(Old,New) is true for corresponding elements of the two trees.

put_label(+I, +OldTree, +Label, -NewTree)

Constructs NewTree which has the same shape and elements as OldTree, except that the I-th element is Label.

put_label(+I, +OldTree, +Label, -NewTree, +Label)

Constructs NewTree which has the same shape and elements as OldTree, except that the I-th element is changed from OldLabel to NewLabel.

tree_size(+Tree, ?Size)

Calculates as Size the number of elements in the Tree.

tree_to_list(+Tree, ?List)

Is the converse operation to list_to_tree/2. Any mapping or checking operation can be done by converting the tree to a list, mapping or checking the list, and converting the result, if any, back to a tree.


Node:UGraphs, Next:, Previous:Trees, Up:Top

Unweighted Graph Operations

Directed and undirected graphs are fundamental data structures representing arbitrary relationships between data objects. This package provides a Prolog implementation of directed graphs, undirected graphs being a special case of directed graphs.

An unweighted directed graph (ugraph) is represented as a list of (vertex-neighbors) pairs, where the pairs are in standard order (as produced by keysort with unique keys) and the neighbors of each vertex are also in standard order (as produced by sort), every neighbor appears as a vertex even if it has no neighbors itself, and no vertex is a neighbor to itself.

An undirected graph is represented as a directed graph where for each edge (U,V) there is a symmetric edge (V,U).

An edge (U,V) is represented as the term U-V. U and V must be distinct.

A vertex can be any term. Two vertices are distinct iff they are not identical (==).

A path from u to v is represented as a list of vertices, beginning with u and ending with v. A vertex cannot appear twice in a path. A path is maximal in a graph if it cannot be extended.

A tree is a tree-shaped directed graph (all vertices have a single predecessor, except the root node, which has none).

A strongly connected component of a graph is a maximal set of vertices where each vertex has a path in the graph to every other vertex.

Sets are represented as ordered lists (see Ordsets).

To load the package, enter the query

| ?- use_module(library(ugraphs)).

The following predicates are defined for directed graphs.


vertices_edges_to_ugraph(+Vertices, +Edges, -Graph)
Is true if Vertices is a list of vertices, Edges is a list of edges, and Graph is a graph built from Vertices and Edges. Vertices and Edges may be in any order. The vertices mentioned in Edges do not have to occur explicitly in Vertices. Vertices may be used to specify vertices that are not connected by any edges.
vertices(+Graph, -Vertices)
Unifies Vertices with the vertices in Graph.
edges(+Graph, -Edges)
Unifies Edges with the edges in Graph.
add_vertices(+Graph1, +Vertices, -Graph2)
Graph2 is Graph1 with Vertices added to it.
del_vertices(+Graph1, +Vertices, -Graph2)
Graph2 is Graph1 with Vertices and all edges to and from them removed from it.
add_edges(+Graph1, +Edges, -Graph2)
Graph2 is Graph1 with Edges and their "to" and "from" vertices added to it.
del_edges(+Graph1, +Edges, -Graph2)
Graph2 is Graph1 with Edges removed from it.
transpose(+Graph, -Transpose)
Transpose is the graph computed by replacing each edge (u,v) in Graph by its symmetric edge (v,u). Takes O(N^2) time.
neighbors(+Vertex, +Graph, -Neighbors)
neighbours(+Vertex, +Graph, -Neighbors)
Vertex is a vertex in Graph and Neighbors are its neighbors.
complement(+Graph, -Complement)
Complement is the complement graph of Graph, i.e. the graph that has the same vertices as Graph but only the edges that are not in Graph.
compose(+G1, +G2, -Composition)
Computes Composition as the composition of two graphs, which need not have the same set of vertices.
transitive_closure(+Graph, -Closure)
Computes Closure as the transitive closure of Graph in O(N^3) time.
symmetric_closure(+Graph, -Closure)
Computes Closure as the symmetric closure of Graph, i.e. for each edge (u,v) in Graph, add its symmetric edge (v,u). Takes O(N^2) time. This is useful for making a directed graph undirected.
top_sort(+Graph, -Sorted)
Finds a topological ordering of a Graph and returns the ordering as a list of Sorted vertices. Fails iff no ordering exists, i.e. iff the graph contains cycles. Takes O(N^2) time.
max_path(+V1, +V2, +Graph, -Path, -Cost)
Path is a longest path of cost Cost from V1 to V2 in Graph, there being no cyclic paths from V1 to V2. Takes O(N^2) time.
min_path(+V1, +V2, +Graph, -Path, -Cost)
Path is a shortest path of cost Cost from V1 to V2 in Graph. Takes O(N^2) time.
min_paths(+Vertex, +Graph, -Tree)
Tree is a tree of all the shortest paths from Vertex to every other vertex in Graph. This is the single-source shortest paths problem.
path(+Vertex, +Graph, -Path)
Given a Graph and a Vertex of Graph, returns a maximal Path rooted at Vertex, enumerating more paths on backtracking.
reduce(+Graph, -Reduced)
Reduced is the reduced graph for Graph. The vertices of the reduced graph are the strongly connected components of Graph. There is an edge in Reduced from u to v iff there is an edge in Graph from one of the vertices in u to one of the vertices in v.
reachable(+Vertex, +Graph, -Reachable)
Given a Graph and a Vertex of Graph, returns the set of vertices that are reachable from that Vertex, including Vertex itself. Takes O(N^2) time.
random_ugraph(+P, +N, -Graph)
Where P is a probability, unifies Graph with a random graph of vertices 1..N where each possible edge is included with probability P.

The following predicates are defined for undirected graphs only.


min_tree(+Graph, -Tree, -Cost)
Tree is a spanning tree of Graph with cost Cost, if it exists.
clique(+Graph, +K, -Clique)
Clique is a maximal clique (complete subgraph) of N vertices of Graph, where N>=K. N is not necessarily maximal.
independent_set(+Graph, +K, -Set)
Set is a maximal independent (unconnected) set of N vertices of Graph, where N>=K. N is not necessarily maximal.
coloring(+Graph, +K, -Coloring)
colouring(+Graph, +K, -Coloring)
Coloring is a mapping from vertices to colors 1..N of Graph such that all edges have distinct end colors, where N=<K. The mapping is represented as an ordered list of Vertex-Color pairs. N is not necessarily minimal.


Node:WGraphs, Next:, Previous:UGraphs, Up:Top

Weighted Graph Operations

A weighted directed graph (wgraph) is represented as a list of (vertex-edgelist) pairs, where the pairs are in standard order (as produced by keysort with unique keys), the edgelist is a list of (neighbor-weight) pair also in standard order (as produced by keysort with unique keys), every weight is a nonnegative integer, every neighbor appears as a vertex even if it has no neighbors itself, and no vertex is a neighbor to itself.

An undirected graph is represented as a directed graph where for each edge (U,V) there is a symmetric edge (V,U).

An edge (U,V) with weight W is represented as the term U-(V-W). U and V must be distinct.

A vertex can be any term. Two vertices are distinct iff they are not identical (==).

A path from u to v is represented as a list of vertices, beginning with u and ending with v. A vertex cannot appear twice in a path. A path is maximal in a graph if it cannot be extended.

A tree is a tree-shaped directed graph (all vertices have a single predecessor, except the root node, which has none).

A strongly connected component of a graph is a maximal set of vertices where each vertex has a path in the graph to every other vertex.

Sets are represented as ordered lists (see Ordsets).

To load the package, enter the query

| ?- use_module(library(wgraphs)).

The following predicates are defined for directed graphs.


wgraph_to_ugraph(+WeightedGraph, -Graph)
Graph has the same vertices and edges as WeightedGraph, except the edges of Graph are unweighted.
ugraph_to_wgraph(+Graph, -WeightedGraph)
WeightedGraph has the same vertices and edges as Graph, except the edges of WeightedGraph all have weight 1.
vertices_edges_to_wgraph(+Vertices, +Edges, -WeightedGraph)
Vertices is a list of vertices, Edges is a list of edges, and WeightedGraph is a graph built from Vertices and Edges. Vertices and Edges may be in any order. The vertices mentioned in Edges do not have to occur explicitly in Vertices. Vertices may be used to specify vertices that are not connected by any edges.
vertices(+WeightedGraph, -Vertices)
Unifies Vertices with the vertices in WeightedGraph.
edges(+WeightedGraph, -Edges)
Unifies Edges with the edges in WeightedGraph.
add_vertices(+WeightedGraph1, +Vertices, -WeightedGraph2)
WeightedGraph2 is WeightedGraph1 with Vertices added to it.
del_vertices(+WeightedGraph1, +Vertices, -WeightedGraph2)
WeightedGraph2 is WeightedGraph1 with Vertices and all edges to and from them removed from it.
add_edges(+WeightedGraph1, +Edges, -WeightedGraph2)
WeightedGraph2 is WeightedGraph1 with Edges and their "to" and "from" vertices added to it.
del_edges(+WeightedGraph1, +Edges, -WeightedGraph2)
WeightedGraph2 is WeightedGraph1 with Edges removed from it.
transpose(+WeightedGraph, -Transpose)
Transpose is the graph computed by replacing each edge (u,v) in WeightedGraph by its symmetric edge (v,u). It can only be used one way around. Takes O(N^2) time.
neighbors(+Vertex, +WeightedGraph, -Neighbors)
neighbours(+Vertex, +WeightedGraph, -Neighbors)
Vertex is a vertex in WeightedGraph and Neighbors are its weighted neighbors.
transitive_closure(+WeightedGraph, -Closure)
Computes Closure as the transitive closure of WeightedGraph in O(N^3) time.
symmetric_closure(+WeightedGraph, -Closure)
Computes Closure as the symmetric closure of WeightedGraph, i.e. for each edge (u,v) in WeightedGraph, add its symmetric edge (v,u). Takes O(N^2) time. This is useful for making a directed graph undirected.
top_sort(+WeightedGraph, -Sorted)
Finds a topological ordering of a WeightedGraph and returns the ordering as a list of Sorted vertices. Fails iff no ordering exists, i.e. iff the graph contains cycles. Takes O(N^2) time.
max_path(+V1, +V2, +WeightedGraph, -Path, -Cost)
Path is a maximum-cost path of cost Cost from V1 to V2 in WeightedGraph, there being no cyclic paths from V1 to V2. Takes O(N^2) time.
min_path(+V1, +V2, +WeightedGraph, -Path, -Cost)
Path is a minimum-cost path of cost Cost from V1 to V2 in WeightedGraph. Takes O(N^2) time.
min_paths(+Vertex, +WeightedGraph, -Tree)
Tree is a tree of all the minimum-cost paths from Vertex to every other vertex in WeightedGraph. This is the single-source minimum-cost paths problem.
path(+Vertex, +WeightedGraph, -Path)
Given a WeightedGraph and a Vertex of WeightedGraph, returns a maximal Path rooted at Vertex, enumerating more paths on backtracking.
reduce(+WeightedGraph, -Reduced)
Reduced is the reduced graph for WeightedGraph. The vertices of the reduced graph are the strongly connected components of WeightedGraph. There is an edge in Reduced from u to v iff there is an edge in WeightedGraph from one of the vertices in u to one of the vertices in v.
reachable(+Vertex, +WeightedGraph, -Reachable)
Given a WeightedGraph and a Vertex of WeightedGraph, returns the set of vertices that are reachable from that Vertex. Takes O(N^2) time.
random_wgraph(+P, +N, +W, -WeightedGraph)
Where P is a probability, unifies WeightedGraph with a random graph of vertices 1..N where each possible edge is included with probability P and random weight in 1..W.

The following predicate is defined for undirected graphs only.


min_tree(+WeightedGraph, -Tree, -Cost)
Tree is a minimum-cost spanning tree of WeightedGraph with cost Cost, if it exists.


Node:Sockets, Next:, Previous:WGraphs, Up:Top

Socket I/O

This library package defines a number of predicates manipulating sockets. They are all rather straight-forward interfaces to the corresponding BSD-type socket functions with the same name (except current_host/1). The reader should therefore study the appropriate documents for a deeper description.

The Domain is either the atom 'AF_INET' or 'AF_UNIX'. They correspond directly to the same domains in BSD-type sockets. 'AF_UNIX' may not be available on non-UNIX platforms.

An Address is either 'AF_INET'(Host,Port) or 'AF_UNIX'(SocketName). Host is an atomic hostname, Port is a portnumber and SocketName is an atom denoting a socket. A reader familiar with BSD sockets will understand this immediately.

All streams below can be both read from and written on. All I/O-predicates operating on streams can be used, for example read/2, write/2, format/3, current_stream/3, etc. Socket streams are block buffered both on read and write by default. This can be changed by calling socket_buffering/4.

To load the package, enter the query

| ?- use_module(library(sockets)).
socket(+Domain, -Socket)

A socket Socket in the domain Domain is created.

socket_close(+Socket)

Socket is closed. Sockets used in socket_connect/2 should not be closed by socket_close/1 as they will be closed when the corresponding stream is closed.

socket_bind(+Socket, 'AF_UNIX'(+SocketName))
socket_bind(+Socket, 'AF_INET'(?Host,?Port))

The socket Socket is bound to the address. If Port is uninstantiated, the operative system picks a port number to which Port is bound.

socket_connect(+Socket, 'AF_UNIX'(+SocketName), -Stream)
socket_connect(+Socket, 'AF_INET'(+Host,+Port), -Stream)

The socket Socket is connected to the address. Stream is a special stream on which items can be both read and written.

socket_listen(+Socket, +Length)

The socket Socket is defined to have a maximum backlog queue of Length pending connections.

socket_accept(+Socket, -Stream)
socket_accept(+Socket, -Client, -Stream)

The first connection to socket Socket is extracted. The stream Stream is opened for read and write on this connection. For the 'AF_INET' domain, Client will unified with an atom containing the Internet host address of the connecting entity in numbers-and-dots notation. For other domains, Client will not be used.

socket_buffering(+Stream, +Direction, -OldBuf, +NewBuf)

The buffering in the Direction of the socket stream Stream is changed from OldBuf to NewBuf. Direction should be read or write. OldBuf and NewBuf should be unbuf for unbuffered I/O or fullbuf for block buffered I/O.

socket_select(+TermsSockets, -NewTermsStreams, +TimeOut, +Streams, -ReadStreams)

The list of streams in Streams is checked for readable characters. A stream can be any stream associated with an I/O descriptor. The list ReadStreams returns the streams with readable data.

socket_select/5 also waits for connections to the sockets specified by TermsSockets. This argument should be a list of Term-Socket pairs, where Term, which can be any term, is used as an identifier. NewTermsStreams is a list of Term-connection(Client,Stream) pairs, where Stream is a new stream open for communicating with a process connecting to the socket identified with Term, Client is the client host address (see socket_accept/3).

If TimeOut is instantiated to off, the predicate waits until something is available. If TimeOut is S:U the predicate waits at most S seconds and U microseconds. Both S and U must be integers >=0. If there is a timeout, ReadStreams and NewTermsStreams are [].

socket_select(+Sockets, -NewStreams, +TimeOut, +Streams, -ReadStreams)
socket_select(+Socket, -NewStream, +TimeOut, +Streams, -ReadStreams)
socket_select(+Sockets, -NewStreams, -NewClients, +TimeOut, +Streams, -ReadStreams)
socket_select(+Socket, -NewStream, -NewClient, +TimeOut, +Streams, -ReadStreams)

These forms, which are provided for backward compatibility only, differs in how sockets are specified and new streams returned.

socket_select/[5,6] also wait for connections to the sockets in the list Sockets. NewStreams is the list of new streams opened for communicating with the connecting processes. NewClients is the corresponding list of client host addresses (see socket_accept/3).

The second form requires one socket (not a list) for the first argument and returns a stream, NewStream, if a connection is made.

current_host(?HostName)

HostName is unified with the fully qualified name of the machine the process is executing on. The call will also succeed if HostName is instantiated to the unqualified name of the machine.

hostname_address(+HostName, -HostAddress)
hostname_address(-HostName, +HostAddress)

The Internet host is resolved given either the host name or address. HostAddress should be an atom containing the Internet host address in numbers-and-dots notation. The predicate will fail if the host name or address cannot be resolved.


Node:Linda Library, Next:, Previous:Sockets, Up:Top

Linda--Process Communication

Linda is a concept for process communication.

For an introduction and a deeper description, see [Carreiro & Gelernter 89a] or [Carreiro & Gelernter 89b], respectively.

One process is running as a server and one or more processes are running as clients. The processes are communicating with sockets and supports networks.

The server is in principle a blackboard on which the clients can write (out/1), read (rd/1) and remove (in/1) data. If the data is not present on the blackboard, the predicates suspend the process until they are available.

There are some more predicates besides the basic out/1, rd/1 and in/1. The in_noblock/1 and rd_noblock/1 does not suspend if the data is not available--they fail instead. A blocking fetch of a conjunction of data can be done with in/2 or rd/2.

Example: A simple producer-consumer. In client 1:

producer :-
       produce(X),
       out(p(X)),
       producer.

produce(X) :- .....

In client 2:

consumer :-
       in(p(A)),
       consume(A),
       consumer.

consume(A) :- .....

Example: Synchronization

       ...,
       in(ready),  %Waits here until someone does out(ready)
       ...,

Example: A critical region

       ...,
       in(region_free),  % wait for region to be free
       critical_part,
       out(region_free), % let next one in
       ...,

Example: Reading global data

       ...,
       rd(data(Data)),
       ...,

or, without blocking:
       ...,
       rd_noblock(data(Data)) ->
             do_something(Data)
       ;     write('Data not available!'),nl
       ),
       ...,

Example: Waiting for one of several events

       ...,
       in([e(1),e(2),...,e(n)], E),
%  Here is E instantiated to the first tuple that became available
       ...,


Node:Server, Next:, Previous:Linda Library, Up:Linda Library

Server

The server is the process running the "blackboard process". It is an ordinary SICStus process which can be run on a separate machine if necessary.

To load the package, enter the query

| ?- use_module(library('linda/server')).

and start the server with linda/0 or linda/1.

linda

Starts a Linda-server in this SICStus. The network address is written to current output stream as Host:PortNumber.

linda(+Hook)

Starts a Linda-server in this SICStus. When it is started, a goal passed in Hook is evaluated. Hook must have the form Address-Goal where Address must be unifiable with Host:Port and Goal must be instantiated to a goal. Example:

| ?- linda((Host:Port)-(my_module:mypred(Host,Port))).
will call mypred/2 in module my_module when the server is started. mypred/2 could start the client-processes, save the address for the clients etc. Note that the module must be present in Goal.


Node:Client, Previous:Server, Up:Linda Library

Client

The clients are one or more sicstus processes which have connection(s) to the server.

To load the package, enter the query

| ?- use_module(library('linda/client')).

Some of the following predicates fail if they don't receive an answer from the Linda-server in a reasonable amount of time. That time is set with the predicate linda_timeout/2.

linda_client(+Address)

Establishes a connection to a Linda-server specified by Address. The Address is of the format Host:PortNumber as given by linda/0 and linda/1.

It is not possible to be connected to two Linda-servers in the same time.

This predicate can fail due to a timeout.

close_client

Closes the connection to the Linda-server.

linda_timeout(?OldTime, ?NewTime)

This predicate controls Linda's timeout. OldTime is unified with the old timeout and then timeout is set to NewTime. The value is either off or of the form Seconds:Milliseconds. The former value indicates that the timeout mechanism is disabled, that is, eternal waiting. The latter form is the timeout-time.

out(+Tuple)

Places the tuple Tuple in Linda's tuple-space.

in(?Tuple)

Removes the tuple Tuple from Linda's tuple-space if it is there. If not, the predicate blocks until it is available (that is, someone performs an out/1).

in_noblock(?Tuple)

Removes the tuple Tuple from Linda's tuple-space if it is there. If not, the predicate fails.

This predicate can fail due to a timeout.

in(+TupleList, ?Tuple)

As in/1 but succeeds when either of the tuples in TupleList is available. Tuple is unified with the fetched tuple. If that unification fails, the tuple is not reinserted in the tuple-space.

rd(?Tuple)

Succeeds if Tuple is available in the tuple-space, suspends otherwise until it is available. Compare this with in/1: the tuple is not removed.

rd_noblock(?Tuple)

Succeeds if Tuple is available in the tuple-space, fails otherwise.

This predicate can fail due to a timeout.

rd(+TupleList, ?Tuple)

As in/2 but does not remove any tuples.

bagof_rd_noblock(?Template, +Tuple, ?Bag)

Bag is the list of all instances of Template such that Tuple exists in the tuple-space.

The behavior of variables in Tuple and Template is as in bagof/3. The variables could be existentially quantified with ^/2 as in bagof/3.

The operation is performed as an atomic operation.

This predicate can fail due to a timeout.

Example: Assume that only one client is connected to the server and that the tuple-space initially is empty.

| ?- out(x(a,3)), out(x(a,4)), out(x(b,3)), out(x(c,3)).

yes
| ?- bagof_rd_noblock(C-N, x(C,N), L).

C = _32,
L = [a-3,a-4,b-3,c-3],
N = _52 ?

yes
| ?- bagof_rd_noblock(C, N^x(C,N), L).

C = _32,
L = [a,a,b,c],
N = _48 ?

yes


Node:DB, Next:, Previous:Linda Library, Up:Top

DB - External Storage of Terms

This library module is obsolete and has been replaced by library(bdb). It is included in the SICStus distribution for backwards compatibility only. It will be removed in the next major release.

The sources to library(db) can be downloaded freely from

ftp://ftp.sics.se/archive/sicstus3/libdb.tgz


Node:BDB, Next:, Previous:DB, Up:Top

External Storage of Terms (Berkeley DB)

This library module handles storage and retrieval of terms on files. By using indexing, the store/retrieve operations are efficient also for large data sets. The package is an interface to the Berkeley DB toolset.

The package is loaded by the query:

| ?- use_module(library(bdb)).


Node:Basics, Next:, Previous:BDB, Up:BDB

Basics

The idea is to get a behavior similar to assert/1, retract/1 and clause/2 but the terms are stored on files instead of in primary memory.

The differences compared with the internal database are:

Some commercial databases can't store non-ground terms or more than one instance of a term. This library module can however store terms of either kind.


Node:Current Limitations, Next:, Previous:Basics, Up:BDB

Current Limitations


Node:Berkeley DB, Next:, Previous:Current Limitations, Up:BDB

Berkeley DB

This library module is an interface to the Berkeley DB toolset to support persistent storage of Prolog terms. Some of the notions of Berkeley DB are directly inherited, e.g. the environment.

The interface uses the Concurrent Access Methods product of Berkeley DB. This means that multiple processes can open the same database but transactions and disaster recovery are not supported.

The environment and the database files are ordinary Berkeley DB entities which means that the standard support utilities (e.g. db_stat) will work.


Node:The DB-Spec Informal Description, Next:, Previous:Berkeley DB, Up:BDB

The DB-Spec--Informal Description

The db-spec defines which functors are allowed and which parts of a term are used for indexing in a database. The syntax of a spec resembles to that of the mode specification. The db-spec is a list of atoms and compound terms where the arguments are either + or -. A term can be inserted in the database if there is a spec in the spec list with the same functor.

Multilevel indexing is not supported, terms have to be "flattened".

Every spec with the functor of the indexed term specifies an indexing. Every argument where there is a + in the spec is indexed on.

The idea of the db-spec is illustrated with a few examples. (A section further down explains the db-spec in a more formal way).

Given a spec of [f(+,-), .(+,-), g, f(-,+)] the indexing works as follows. (The parts with indexing are underlined.)

Term Store Fetch

g(x,y) domain error domain error

f(A,B) f(A,B) instantiation error
-

f(a,b) f(a,b) f(a,b) f(a,b)
- - - - - -

[a,b] .(a,.(b,[])) .(a,.(b,[]))
- - - -

g g g
- -

The specification [f(+,-), f(-,+)] is different from [f(+,+)]. The first specifies that two indices are to be made whereas the second specifies that only one index is to be made on both arguments of the term.


Node:Predicates, Next:, Previous:The DB-Spec Informal Description, Up:BDB

Predicates


Node:Conventions, Next:, Previous:Predicates, Up:Predicates

Conventions

The following conventions are used in the predicate descriptions below.


Node:The environment, Next:, Previous:Conventions, Up:Predicates

The environment

To enable sharing of databases between process, programs have to create environments and the databases should be opened in these environments. A database can be shared between processes that open it in the same environment. An environment physically consists of a directory containing the files needed to enable sharing databases between processes. The directory of the environment has to be located in a local file system.

Databases can be opened outside any environment (see db_open/4), but in that case a process writing the database must ensure exclusive access or the behavior of the predicates is undefined.


Node:Memory leaks, Next:, Previous:The environment, Up:Predicates

Memory leaks

In order to avoid memory leaks, environments, databases and iterators should always be closed. Consider using call_cleanup/2 to automate the closing/deallocation of these objects. You can always use db_current_env/1, db_current/5 and db_current_iterator/3 to enumerate the currently living objects.


Node:The predicates, Previous:Memory leaks, Up:Predicates

The predicates

db_open_env(+EnvName, -EnvRef)
db_open_env(+EnvName, +CacheSize, -EnvRef)

Opens an environment with the name EnvName. A directory with this name is created for the environment if necessary. EnvName is not subject to absolute_file_name/2 conversion.

By using db_open_env/3 one can specify the size of the cache: CacheSize is the (integer) size of the cache in kilobytes. The size of the cache cannot be less than 20 kilobytes. db_open_env/2 will create a cache of the system's default size.

The size of the cache is determined when the environment is created and cannot be changed by future openings.

A process cannot open the same environment more than once.

db_close_env(+EnvRef)

Closes an environment. All databases opened in the environment will be closed as well. abort/0 does not close environments.

db_current_env(?EnvName, ?EnvRef)

Unifies the arguments with the open environments. This predicate can be used for enumerating all currently open environments through backtracking.

db_open(+DBName, +Mode, ?SpecList, -DBRef)
db_open(+DBName, +Mode, ?SpecList, +EnvRef, -DBRef)

Opens a database with the name DBName. The database physically consists of a directory with the same name, containing the files that make up the database. If the directory does not exist, it is created. In that case Mode must be update and the db-spec SpecList must be ground. If an existing database is opened and Mode is read or update, SpecList is unified with the db-spec given when the database was created. If the unification fails an error is raised. DBRef is unified with a reference to the opened database. DBName is not subject to absolute_file_name/2 conversion.

If Mode is enumerate then the indexing specification is not read, and SpecList is left unbound.

db_open/5 opens the database in the environment referred to by EnvRef. db_open/4 opens the database outside any environment. (db_open/4 is equivalent to calling db_open/5 with EnvRef bound to the atom none.)

To avoid inconsistency, if multiple processes open the same database with db_open/4 then all of them should do that with Mode set to read or enumerate. (This is not enforced by the system.)

db_close(+DBRef)

Closes the database referenced by DBRef. Any iterators opened in the database will be deallocated. abort/0 does not close databases.

db_current(?DBName, ?Mode, ?SpecList, ?EnvRef, ?DBRef)

Unifies the arguments with the open databases. This predicate can be used to enumerate all currently open databases through backtracking. If the database was opened with db_open/4 then EnvRef will be unified with the atom none.

db_store(+DBRef, +Term, -TermRef)

Stores Term in the database DBRef. TermRef is unified with a corresponding term reference. The functor of Term must match the functor of a spec in the db-spec associated with DBRef.

db_fetch(+DBRef, ?Term, ?TermRef)

Unifies Term with a term from the database DBRef. At the same time, TermRef is unified with a corresponding term reference. Backtracking over the predicate unifies with all terms matching Term.

If TermRef is not instantiated then both the functor and the instantiatedness of Term must match a spec in the db-spec associated with DBRef.

If TermRef is instantiated, the referenced term is read and unified with Term.

If you simply want to find all matching terms, it is more efficient to use db_findall/5 or db_enumerate/3.

db_findall(+DBRef, +Template, +Term, :Goal, ?Bag)

Unifies Bag with the list of instances of Template in all proofs of Goal found when Term is unified with a matching term from the database DBRef. Both the functor and the instantiatedness of Term must match a spec in the db-spec associated with DBRef. Conceptually, this predicate is equivalent to findall(Template, (db_fetch(DBRef, Term, _), Goal), Bag).

db_erase(+DBRef, +TermRef)
db_erase(+DBRef, +TermRef, +Term)

Deletes the term from the database DBRef that is referenced by TermRef.

In the case of db_erase/2 the term associated with TermRef has to be looked up. db_erase/3 assumes that the term Term is identical with the term associated with TermRef (modulo variable renaming). If this is not the case, the behavior is undefined.

db_enumerate(+DBRef, ?Term, ?TermRef)

Unifies Term with a term from the database DBRef. At the same time, TermRef is unified with a corresponding term reference. Backtracking over the predicate unifies with all terms matching Term.

Implemented by linear search--the db-spec associated with DBRef is ignored. It is not useful to call this predicate with TermRef instantiated.

db_compress(+DBRef, +DBName)
db_compress(+DBRef, +DBName, +SpecList)
Copies the database given by DBRef to a new database named by DBName. The new database will be a compressed version of the first one in the sense that it will not have "holes" resulting from deletion of terms. Deleted term references will also be reused, which implies that references that refer to terms in the old database will be invalid in the new one.

db_compress/2 looks for a database with the db-spec of the original one. db_compress/3 stores the terms found in the original database with the indexing specification SpecList. db_compress/2 cannot be used if the database DBRef was opened in mode enumerate.

If the database DBName already exists then the terms of DBRef will be appended to it. Of course DBName must have an indexing specification which enables the terms in DBRef to be inserted into it.

In the case of db_compress/3 if the database DBName does not exist, then SpecList must be a valid indexing specification.

db_make_iterator(+DBRef, -Iterator)
db_make_iterator(+DBRef, +Term, -Iterator)

Creates a new iterator and unifies it with Iterator. Iterators created with db_make_iterator/2 iterate through the whole database. Iterators created with db_make_iterator/3 iterate through the terms that would be found by db_fetch(DBRef, Term, _).

Every iterator created by db_make_iterator/[2,3] must be destroyed with db_iterator_done/1.

db_iterator_next(+Iterator, ?Term, ?TermRef)

Iterator advances to the next term, Term and TermRef is unified with the term and its reference pointed to by Iterator. If there is no next term, the predicate fails.

db_iterator_done(+Iterator)

Deallocates Iterator, which must not be used anymore. abort/0 does not deallocate iterators.

db_current_iterator(?DBRef, ?Term, ?Iterator)

Unifies the the variables with the respective properties of the living iterators. This predicate can be used to enumerate all currently alive iterators through backtracking. If Iterator was made with db_make_iterator/2 then Term will be left unbound.


Node:An Example Session, Next:, Previous:Predicates, Up:BDB

An Example Session

| ?- db_open('/tmp/db', update, [a(+,-)], '$db_env'(-33470544), DBRef).

DBRef = '$db'(-33470432) ?

yes
| ?- db_store('$db'(-33470432), a(b,1), _).

yes
| ?- db_store('$db'(-33470432), a(c,2), _).

yes
| ?- db_fetch('$db'(-33470432), a(b,X), _).

X = 1 ? ;

no
| ?- db_enumerate('$db'(-33470432), X, _).

X = a(b,1) ? ;

X = a(c,2) ? ;

no
| ?- db_current(DBName, Mode, Spec, EnvRef, DBRef).

Mode = update,
Spec = [a(+,-)],
DBRef = '$db'(-33470432),
DBName = '/tmp/db',
EnvRef = '$db_env'(-33470544) ? ;

no
| ?- db_close_env('$db_env'(-33470544)).

yes


Node:The DB-Spec, Previous:An Example Session, Up:BDB

The DB-Spec

A db-spec has the form of a speclist:

speclist
= [spec1, ..., specM]
spec
= functor(argspec1, ..., argspecN)
argspec
= + | -
where functor is a Prolog atom. The case N = 0 is allowed.

A spec F(argspec1, ..., argspecN) is applicable to any nonvar term with principal functor F/N.

When storing a term T we generate a hash code for every applicable spec in the db-spec, and a reference to T is stored with each of them. (More precisely with each element of the set of generated hash codes). If T contains nonvar elements on each + position in the spec, then the hash code depends on each of these elements. If T does contain some variables on + position, then the hash code depends only on the functor of T.

When fetching a term Q we look for an applicable spec for which there are no variables in Q on positions maked +. If no applicable spec can be found a domain error is raised. If no spec can be found where on each + position a nonvar term occurs in Q an instantiation error is raised. Otherwise, we choose the the spec with the most + postitions in it breaking ties by choosing the leftmost one.

The terms that contain nonvar terms on every + postition will be looked up using indexing based on the principal functor of the term and the principal functor of terms on + postitions. The other (more general) terms will be looked up using an indexing based on the principal functor of the term only.

As can be seen, storing and fetching terms with variables on + positions are not vigorously supported operations.


Node:CLPB, Next:, Previous:BDB, Up:Top

Boolean Constraint Solver

The clp(B) system provided by this library module is an instance of the general Constraint Logic Programming scheme introduced in [Jaffar & Michaylov 87]. It is a solver for constraints over the Boolean domain, i.e. the values 0 and 1. This domain is particularly useful for modeling digital circuits, and the constraint solver can be used for verification, design, optimization etc. of such circuits.

To load the solver, enter the query:

| ?- use_module(library(clpb)).

The solver contains predicates for checking the consistency and entailment of a constraint wrt. previous constraints, and for computing particular solutions to the set of previous constraints.

The underlying representation of Boolean functions is based on Boolean Decision Diagrams [Bryant 86]. This representation is very efficient, and allows many combinatorial problems to be solved with good performance.

Boolean expressions are composed from the following operands: the constants 0 and 1 (FALSE and TRUE), logical variables, and symbolic constants, and from the following connectives. P and Q are Boolean expressions, X is a logical variable, Is is a list of integers or integer ranges, and Es is a list of Boolean expressions:

~ P
True if P is false.
P * Q
True if P and Q are both true.
P + Q
True if at least one of P and Q is true.
P # Q
True if exactly one of P and Q is true.
X ^ P
True if there exists an X such that P is true. Same as P[X/0] + P[X/1].
P =:= Q
Same as ~P # Q.
P =\= Q
Same as P # Q.
P =< Q
Same as ~P + Q.
P >= Q
Same as P + ~Q.
P < Q
Same as ~P * Q.
P > Q
Same as P * ~Q.
card(Is, Es)
True if the number of true expressions in Es is a member of the set denoted by Is.

Symbolic constants (Prolog atoms) denote parametric values and can be viewed as all-quantified variables whose quantifiers are placed outside the entire expression. They are useful for forcing certain variables of an equation to be treated as input parameters.


Node:CLPB Interface, Next:, Previous:CLPB, Up:CLPB

Solver Interface

The following predicates are defined:

sat(+Expression)

Expression is a Boolean expression. This checks the consistency of the expression wrt. the accumulated constraints, and, if the check succeeds, tells the constraint that the expression be true.

If a variable X, occurring in the expression, is subsequently unified with some term T, this is treated as a shorthand for the constraint

?- sat(X=:=T).

taut(+Expression, ?Truth)

Expression is a Boolean expression. This asks whether the expression is now entailed by the accumulated constraints (Truth=1), or whether its negation is entailed by the accumulated constraints (Truth=0). Otherwise, it fails.

labeling(+Variables)

Variables is a list of variables. The variables are instantiated to a list of 0s and 1s, in a way that satisfies any accumulated constraints. Enumerates all solutions by backtracking, but creates choicepoints only if necessary.


Node:CLPB Examples, Previous:CLPB Interface, Up:CLPB

Examples


Node:Example 1, Next:, Previous:CLPB Examples, Up:CLPB Examples

Example 1

| ?- sat(X + Y).

sat(X=\=_A*Y#Y) ?

illustrates three facts. First, any accumulated constraints affecting the top-level variables are displayed as floundered goals, since the query is not true for all X and Y. Secondly, accumulated constraints are displayed as sat(V=:=Expr) or sat(V=\=Expr) where V is a variable and Expr is a "polynomial", i.e. an exclusive or of conjunctions of variables and constants. Thirdly, _A had to be introduced as an artificial variable, since Y cannot be expressed as a function of X. That is, X + Y is true iff there exists an _A such that X=\=_A*Y#Y. Let's check it!

| ?- taut(_A ^ (X=\=_A*Y#Y) =:= X + Y, T).

T = 1 ?

verifies the above answer. Notice that the formula in this query is a tautology, and so it is entailed by an empty set of constraints.


Node:Example 2, Next:, Previous:Example 1, Up:CLPB Examples

Example 2

| ?- taut(A =< C, T).

no
| ?- sat(A =< B), sat(B =< C), taut(A =< C, T).

T = 1,
sat(A=:=_A*_B*C),
sat(B=:=_B*C) ?

| ?- taut(a, T).

T = 0 ?

yes
| ?- taut(~a, T).

T = 0 ?

illustrates the entailment predicate. In the first query, the expression "A implies C" is neither known to be true nor false, so the query fails. In the second query, the system is told that "A implies B" and "B implies C", so "A implies C" is entailed. The expressions in the third and fourth queries are to be read "for each a, a is true" and "for each a, a is false", respectively, and so T = 0 in both cases since both are unsatisfiable. This illustrates the fact that the implicit universal quantifiers introduced by symbolic constants are placed in front of the entire expression.


Node:Example 3, Next:, Previous:Example 2, Up:CLPB Examples

Example 3

| ?- [user].
| adder(X, Y, Sum, Cin, Cout) :-
     sat(Sum =:= card([1,3],[X,Y,Cin])),
     sat(Cout =:= card([2-3],[X,Y,Cin])).
| {user consulted, 40 msec 576 bytes}

yes
| ?- adder(x, y, Sum, cin, Cout).

sat(Sum=:=cin#x#y),
sat(Cout=:=x*cin#x*y#y*cin) ?

yes
| ?- adder(x, y, Sum, 0, Cout).

sat(Sum=:=x#y),
sat(Cout=:=x*y) ?

yes
| ?- adder(X, Y, 0, Cin, 1), labeling([X,Y,Cin]).

Cin = 0,
X = 1,
Y = 1 ? ;

Cin = 1,
X = 0,
Y = 1 ? ;

Cin = 1,
X = 1,
Y = 0 ? ;

illustrates the use of cardinality constraints and models a one-bit adder circuit. The first query illustrates how representing the input signals by symbolic constants forces the output signals to be displayed as functions of the inputs and not vice versa. The second query computes the simplified functions obtained by setting carry-in to 0. The third query asks for particular input values satisfying sum and carry-out being 0 and 1, respectively.


Node:Example 4, Previous:Example 3, Up:CLPB Examples

Example 4

The predicate fault/3 below describes a 1-bit adder consisting of five gates, with at most one faulty gate. If one of the variables Fi is equal to 1, the corresponding gate is faulty, and its output signal is undefined (i.e., the constraint representing the gate is relaxed).

Assuming that we have found some incorrect output from a circuit, we are interesting in finding the faulty gate. Two instances of incorrect output are listed in fault_ex/2:

fault([F1,F2,F3,F4,F5], [X,Y,Cin], [Sum,Cout]) :-
        sat(
                    card([0-1],[F1,F2,F3,F4,F5]) *
                    (F1 + (U1 =:= X * Cin)) *
                    (F2 + (U2 =:= Y * U3)) *
                    (F3 + (Cout =:= U1 + U2)) *
                    (F4 + (U3 =:= X # Cin)) *
                    (F5 + (Sum =:= Y # U3))
                ).

fault_ex(1, Faults) :- fault(Faults, [1,1,0], [1,0]).
fault_ex(2, Faults) :- fault(Faults, [1,0,1], [0,0]).

To find the faulty gates, we run the query

| ?- fault_ex(I,L), labeling(L).

I = 1,
L = [0,0,0,1,0] ? ;

I = 2,
L = [1,0,0,0,0] ? ;

I = 2,
L = [0,0,1,0,0] ? ;

no

Thus for input data [1,1,0], gate 4 must be faulty. For input data [1,0,1], either gate 1 or gate 3 must be faulty.

To get a symbolic representation of the outputs interms of the input, we run the query

| ?- fault([0,0,0,0,0], [x,y,cin], [Sum,Cout]).

sat(Cout=:=x*cin#x*y#y*cin),
sat(Sum=:=cin#x#y)

which shows that the sum and carry out signals indeed compute the intended functions if no gate is faulty.


Node:CLPQR, Next:, Previous:CLPB, Up:Top

Constraint Logic Programming over Rationals or Reals


Node:Introduction, Next:, Previous:CLPQR, Up:CLPQR

Introduction

The clp(Q,R) system described in this document is an instance of the general Constraint Logic Programming scheme introduced by [Jaffar & Michaylov 87].

The implementation is at least as complete as other existing clp(R) implementations: It solves linear equations over rational or real valued variables, covers the lazy treatment of nonlinear equations, features a decision algorithm for linear inequalities that detects implied equations, removes redundancies, performs projections (quantifier elimination), allows for linear dis-equations, and provides for linear optimization.

The full clp(Q,R) distribution, including a stand-alone manual and an examples directory that is possibly more up to date than the version in the SICStus Prolog distribution, is available from: http://www.ai.univie.ac.at/clpqr/.


Node:Referencing CLPQR, Next:, Previous:Introduction, Up:Introduction

Referencing this Software

When referring to this implementation of clp(Q,R) in publications, you should use the following reference:

Holzbaur C.: OFAI clp(q,r) Manual, Edition 1.3.3, Austrian Research Institute for Artificial Intelligence, Vienna, TR-95-09, 1995.


Node:Acknowledging CLPQR, Previous:Referencing CLPQR, Up:Introduction

Acknowledgments

The development of this software was supported by the Austrian Fonds zur Foerderung der Wissenschaftlichen Forschung under grant P9426-PHY. Financial support for the Austrian Research Institute for Artificial Intelligence is provided by the Austrian Federal Ministry for Science and Research.

We include a collection of examples that has been distributed with the Monash University version of clp(R) [Heintze et al. 87], and its inclusion into this distribution was kindly permitted by Roland Yap.


Node:CLPQR Interface, Next:, Previous:Introduction, Up:CLPQR

Solver Interface

Until rational numbers become first class citizens in SICStus Prolog, rational arithmetics has to be emulated. Because of the emulation it is too expensive to support arithmetics with automatic coercion between all sorts of numbers, like you find it in CommonLisp, for example.

You must choose whether you want to operate in the field of Q (Rationals) or R (Reals):

| ?- use_module(library(clpq)).

or

| ?- use_module(library(clpr)).

You can also load both modules, but the exported predicates listed below will name-clash (see Importation). You can avoid the interactive resolution dialog if the importation is skipped, e.g. via: use_module(library(clpq),[]),use_module(library(clpr),[]).


Node:Notational Conventions, Next:, Previous:CLPQR Interface, Up:CLPQR Interface

Notational Conventions

Throughout this chapter, the prompts clp(q) ?- and clp(r) ?- are used to differentiate between clp(Q) and clp(R) in exemplary interactions.

In general there are many ways to express the same linear relationship. This degree of freedom is manifest in the fact that the printed manual and an actual interaction with the current version of clp(Q,R) may show syntactically different answer constraints, despite the fact the same semantic relationship is being expressed. There are means to control the presentation; see Variable Ordering. The approximative nature of floating point numbers may also produce numerical differences between the text in this manual and the actual results of clp(R), for a given edition of the software.


Node:Solver Predicates, Next:, Previous:Notational Conventions, Up:CLPQR Interface

Solver Predicates

The solver interface for both Q and R consists of the following predicates which are exported from module(linear).

{+Constraint}

Constraint is a term accepted by the the grammar below. The corresponding constraint is added to the current constraint store and checked for satisfiability. Use the module prefix to distinguish the solvers if both clp(Q) and clp(R) were loaded

| ?- clpr:{Ar+Br=10}, Ar=Br, clpq:{Aq+Bq=10}, Aq=Bq.

Aq = 5,
Ar = 5.0,
Bq = 5,
Br = 5.0

Although clp(Q) and clp(R) are independent modules, you are asking for trouble if you (accidently) share variables between them:

| ?- clpr:{A+B=10}, clpq:{A=B}.
{TYPE ERROR: _118=5.0 - arg 2: expected 'a rational number', found 5.0}

This is because both solvers eventually compute values for the variables and Reals are incompatible with Rationals.

Here is the constraint grammar:

Constraint  -->          C
                      | C , C          conjunction 

C -->          Expr =:= Expr       equation 
              | Expr  =  Expr       equation 
              | Expr  <  Expr       strict inequation 
              | Expr  >  Expr       strict inequation 
              | Expr =<  Expr       nonstrict inequation 
              | Expr >=  Expr       nonstrict inequation 
              | Expr =\= Expr       disequation 

Expr -->     variable              Prolog variable 
            | number             floating point or integer 
            | + Expr             unary plus 
            | - Expr             unary minus 
            | Expr + Expr        addition 
            | Expr - Expr        subtraction 
            | Expr * Expr        multiplication 
            | Expr / Expr        division 
            | abs(Expr)           absolute value 
            | sin(Expr)           trigonometric sine 
            | cos(Expr)           trigonometric cosine 
            | tan(Expr)           trigonometric tangent 
            | pow(Expr,Expr)      raise to the power 
            | exp(Expr,Expr)      raise to the power 
            | min(Expr,Expr)      minimum of the two arguments 
            | max(Expr,Expr)      maximum of the two arguments 
            | #(Const)            symbolic numerical constants 

Conjunctive constraints {C,C} have been made part of the syntax to control the granularity of constraint submission, which will be exploited by future versions of this software. Symbolic numerical constants are provided for compatibility only; see Monash Examples.

entailed(+Constraint)

Succeeds iff the linear Constraint is entailed by the current constraint store. This predicate does not change the state of the constraint store.

clp(q) ?- {A =< 4}, entailed(A=\=5).

{A=<4}
yes

clp(q) ?- {A =< 4}, entailed(A=\=3).

no

inf(+Expr, -Inf)
inf(+Expr, -Inf, +Vector, -Vertex)

Computes the infimum of the linear expression Expr and unifies it with Inf. If given, Vector should be a list of variables relevant to Expr, and Vertex will be unified a list of the same length as Vector containing the values for Vector, such that the infimum is produced when assigned. Failure indicates unboundedness.

sup(+Expr, -Sup)
sup(+Expr, -Sup, +Vector, -Vertex)

Computes the supremum of the linear expression Expr and unifies it with Sup. If given, Vector should be a list of variables relevant to Expr, and Vertex will be unified a list of the same length as Vector containing the values for Vector, such that the supremum is produced when assigned. Failure indicates unboundedness.

clp(q) ?- { 2*X+Y =< 16, X+2*Y =< 11,
            X+3*Y =< 15, Z = 30*X+50*Y
          }, sup(Z, Sup, [X,Y], Vertex).

Sup = 310,
Vertex = [7,2],
{Z=30*X+50*Y},
{X+1/2*Y=<8},
{X+3*Y=<15},
{X+2*Y=<11}

minimize(+Expr)

Computes the infimum of the linear expression Expr and equates it with the expression, i.e. as if defined as:

minimize(Expr) :- inf(Expr, Expr).

maximize(+Expr)

Computes the supremum of the linear expression Expr and equates it with the expression.

clp(q) ?- { 2*X+Y =< 16, X+2*Y =< 11,
            X+3*Y =< 15, Z = 30*X+50*Y
          }, maximize(Z).

X = 7,
Y = 2,
Z = 310

bb_inf(+Ints, +Expr, -Inf)

Computes the infimum of the linear expression Expr under the additional constraint that all of variables in the list Ints assume integral values at the infimum. This allows for the solution of mixed integer linear optimization problems; see MIP.

clp(q) ?- {X >= Y+Z, Y > 1, Z > 1}, bb_inf([Y,Z],X,Inf).

Inf = 4,
{Y>1},
{Z>1},
{X-Y-Z>=0}

bb_inf(+Ints, +Expr, -Inf, -Vertex, +Eps)

Computes the infimum of the linear expression Expr under the additional constraint that all of variables in the list Ints assume integral values at the infimum. Eps is a positive number between 0 and 0.5 that specifies how close a number X must be to the next integer to be considered integral: abs(round(X)-X) < Eps. The predicate bb_inf/3 uses Eps = 0.001. With clp(Q), Eps = 0 makes sense. Vertex is a list of the same length as Ints and contains the (integral) values for Ints, such that the infimum is produced when assigned. Note that this will only generate one particular solution, which is different from the situation with minimize/1, where the general solution is exhibited.

ordering(+Spec)

Provides a means to control one aspect of the presentation of the answer constraints; see Variable Ordering.

dump(+Target, -NewVars, -CodedAnswer)

Reflects the constraints on the target variables into a term, where Target and NewVars are lists of variables of equal length and CodedAnswer is the term representation of the projection of constraints onto the target variables where the target variables are replaced by the corresponding variables from NewVars (see Turning Answers into Terms).

clp(q) ?- {A+B =< 10, A>=4},
          dump([A,B],Vs,Cs),
          dump([B],Bp,Cb).

Cb = [_A=<6],
Bp = [_A],
Cs = [_B>=4,_C+_B=<10],
Vs = [_C,_B],
{A>=4},
{A+B=<10}
The current version of dump/3 is incomplete with respect to nonlinear constraints. It only reports nonlinear constraints that are connected to the target variables. The following example has no solution. From the top level's report we have a chance to deduce this fact, but dump/3 currently has no means to collect global constraints ...
q(X) :-
        {X>=10},
        {sin(Z)>3}.

clp(r) ?- q(X), dump([X],V,C).

C = [_A>=10.0],
V = [_A],
clpr:{3.0-sin(_B)<0.0},
{X>=10.0}


Node:Unification, Next:, Previous:Solver Predicates, Up:CLPQR Interface

Unification

Equality constraints are added to the store implicitly each time variables that have been mentioned in explicit constraints are bound - either to another such variable or to a number.

clp(r) ?- {2*A+3*B=C/2}, C=10.0, A=B.

A = 1.0,
B = 1.0,
C = 10.0
Is equivalent modulo rounding errors to
clp(r) ?- {2*A+3*B=C/2, C=10, A=B}.

A = 1.0,
B = 0.9999999999999999,
C = 10.0
The shortcut bypassing the use of {}/1 is allowed and makes sense because the interpretation of this equality in Prolog and clp(R) coincides. In general, equations involving interpreted functors, +/2 in this case, must be fed to the solver explicitly:
clp(r) ?- X=3.0+1.0, X=4.0.

no

Further, variables known by clp(R) may be bound directly to floats only. Likewise, variables known by clp(Q) may be bound directly to rational numbers only; see Rationals. Failing to do so is rewarded with an exception:

clp(q) ?- {2*A+3*B=C/2}, C=10.0, A=B.
{TYPE ERROR: _165=10.0 - arg 2: expected 'a rational number', found 10.0}

This is because 10.0 is not a rational constant. To make clp(Q) happy you have to say:

clp(q) ?- {2*A+3*B=C/2}, C=rat(10,1), A=B.

A = 1,
B = 1,
C = 10

If you use {}/1, you don't have to worry about such details. Alternatively, you may use the automatic expansion facility, check Syntactic Sugar.


Node:Feedback, Previous:Unification, Up:CLPQR Interface

Feedback and Bindings

What was covered so far was how the user populates the constraint store. The other direction of the information flow consists of the success and failure of the above predicates and the binding of variables to numerical values. Example:

clp(r) ?- {A-B+C=10, C=5+5}.

{A = B},
C = 10.0
The linear constraints imply C=10.0 and the solver consequently exports this binding to the Prolog world. The fact that A=B is deduced and represented by the solver but not exported as a binding. More about answer presentation in Projection.


Node:Linearity, Next:, Previous:CLPQR Interface, Up:CLPQR

Linearity and Nonlinear Residues

The clp(Q,R) system is restricted to deal with linear constraints because the decision algorithms for general nonlinear constraints are prohibitively expensive to run. If you need this functionality badly, you should look into symbolic algebra packages. Although the clp(Q,R) system cannot solve nonlinear constraints, it will collect them faithfully in the hope that through the addition of further (linear) constraints they might get simple enough to solve eventually. If an answer contains nonlinear constraints, you have to be aware of the fact that success is qualified modulo the existence of a solution to the system of residual (nonlinear) constraints:

clp(r) ?- {sin(X) = cos(X)}.

clpr:{sin(X)-cos(X)=0.0}
There are indeed infinitely many solutions to this constraint (X = 0.785398 + n*Pi), but clp(Q,R) has no direct means to find and represent them.

The systems goes through some lengths to recognize linear expressions as such. The method is based on a normal form for multivariate polynomials. In addition, some simple isolation axioms, that can be used in equality constraints, have been added. The current major limitation of the method is that full polynomial division has not been implemented. Examples:

This is an example where the isolation axioms are sufficient to determine the value of X.

clp(r) ?- {sin(cos(X)) = 1/2}.

X = 1.0197267436954502

If we change the equation into an inequation, clp(Q,R) gives up:

clp(r) ?- {sin(cos(X)) < 1/2}.

clpr:{sin(cos(X))-0.5<0.0}

The following is easy again:

clp(r) ?- {sin(X+2+2)/sin(4+X) = Y}.

Y = 1.0

And so is this:

clp(r) ?- {(X+Y)*(Y+X)/X = Y*Y/X+99}.

{Y=49.5-0.5*X}

An ancient symbol manipulation benchmark consists in rising the expression X+Y+Z+1 to the 15th power:

clp(q) ?-  {exp(X+Y+Z+1,15)=0}.
clpq:{Z^15+Z^14*15+Z^13*105+Z^12*455+Z^11*1365+Z^10*3003+...
       ... polynomial continues for a few pages ...
       =0}

Computing its roots is another story.


Node:How Nonlinear Residues are made to disappear, Next:, Previous:Linearity, Up:Linearity

How Nonlinear Residues are made to disappear

Binding variables that appear in nonlinear residues will reduce the complexity of the nonlinear expressions and eventually results in linear expressions:

clp(q) ?- {exp(X+Y+1,2) = 3*X*X+Y*Y}.

clpq:{Y*2-X^2*2+Y*X*2+X*2+1=0}

Equating X and Y collapses the expression completely and even determines the values of the two variables:

clp(q) ?- {exp(X+Y+1,2) = 3*X*X+Y*Y}, X=Y.

X = -1/4,
Y = -1/4


Node:Isolation Axioms, Previous:How Nonlinear Residues are made to disappear, Up:Linearity

Isolation Axioms

These axioms are used to rewrite equations such that the variable to be solved for is moved to the left hand side and the result of the evaluation of the right hand side can be assigned to the variable. This allows, for example, to use the exponentiation operator for the computation of roots and logarithms, see below.

A = B * C
Residuates unless B or C is ground or A and B or C are ground.
A = B / C
Residuates unless C is ground or A and B are ground.
X = min(Y,Z)
Residuates unless Y and Z are ground.
X = max(Y,Z)
Residuates unless Y and Z are ground.
X = abs(Y)
Residuates unless Y is ground.
X = pow(Y,Z), X = exp(Y,Z)
Residuates unless any pair of two of the three variables is ground. Example:
clp(r) ?- { 12=pow(2,X) }.

X = 3.5849625007211565

clp(r) ?- { 12=pow(X,3.585) }.

X = 1.9999854993443926

clp(r) ?- { X=pow(2,3.585) }.

X = 12.000311914286545

X = sin(Y)
Residuates unless X or Y is ground. Example:
clp(r) ?- { 1/2 = sin(X) }.

X = 0.5235987755982989

X = cos(Y)
Residuates unless X or Y is ground.
X = tan(Y)
Residuates unless X or Y is ground.


Node:Numerical Precision, Next:, Previous:Linearity, Up:CLPQR

Numerical Precision and Rationals

The fact that you can switch between clp(R) and clp(Q) should solve most of your numerical problems regarding precision. Within clp(Q), floating point constants will be coerced into rational numbers automatically. Transcendental functions will be approximated with rationals. The precision of the approximation is limited by the floating point precision. These two provisions allow you to switch between clp(R) and clp(Q) without having to change your programs.

What is to be kept in mind however is the fact that it may take quite big rationals to accommodate the required precision. High levels of precision are for example required if your linear program is ill-conditioned, i.e., in a full rank system the determinant of the coefficient matrix is close to zero. Another situation that may call for elevated levels of precision is when a linear optimization problem requires exceedingly many pivot steps before the optimum is reached.

If your application approximates irrational numbers, you may be out of space particularly soon.

The following program implements N steps of Newton's approximation for the square root function at point 2.

%
% from file: library('clpqr/examples/root')
%
root(N, R) :-
  root(N, 1, R).

root(0, S, R) :- !, S=R.
root(N, S, R) :-
  N1 is N-1,
  { S1 = S/2 + 1/S },
  root(N1, S1, R).

It is known that this approximation converges quadratically, which means that the number of correct digits in the decimal expansion roughly doubles with each iteration. Therefore the numerator and denominator of the rational approximation have to grow likewise:

clp(q) ?- use_module(library('clpqr/examples/root')).
clp(q) ?- root(3,R),print_decimal(R,70).
1.4142156862 7450980392 1568627450 9803921568 6274509803 9215686274
5098039215

R = 577/408

clp(q) ?- root(4,R),print_decimal(R,70).
1.4142135623 7468991062 6295578890 1349101165 5962211574 4044584905
0192000543

R = 665857/470832

clp(q) ?- root(5,R),print_decimal(R,70).
1.4142135623 7309504880 1689623502 5302436149 8192577619 7428498289
4986231958

R = 886731088897/627013566048

clp(q) ?- root(6,R),print_decimal(R,70).
1.4142135623 7309504880 1688724209 6980785696 7187537723 4001561013
1331132652

R = 1572584048032918633353217/1111984844349868137938112

clp(q) ?- root(7,R),print_decimal(R,70).
1.4142135623 7309504880 1688724209 6980785696 7187537694 8073176679
7379907324

R = 4946041176255201878775086487573351061418968498177 /
    3497379255757941172020851852070562919437964212608

Iterating for 8 steps produces no further change in the first 70 decimal digits of sqrt(2). After 15 steps the approximating rational number has a numerator and a denominator with 12543 digits each, and the next step runs out of memory.

Another irrational number that is easily computed is e. The following program implements an alternating series for 1/e, where the absolute value of last term is an upper bound on the error.

%
% from file: library('clpqr/examples/root')
%
e(N, E) :-
  { Err =:= exp(10,-(N+2)), Half =:= 1/2 },
  inv_e_series(Half, Half, 3, Err, Inv_E),
  { E =:= 1/Inv_E }.

inv_e_series(Term, S0, _, Err, Sum) :-
  { abs(Term) =< Err }, !,
  S0 = Sum.
inv_e_series(Term, S0, N, Err, Sum) :-
  N1 is N+1,
  { Term1 =:= -Term/N, S1 =:= Term1+S0 },
  inv_e_series(Term1, S1, N1, Err, Sum).

The computation of the rational number E that approximates e up to at least 1000 digits in its decimal expansion requires the evaluation of 450 terms of the series, i.e. 450 calls of inv_e_series/5.

clp(q) ?- e(1000,E).

E = 7149056228932760213666809592072842334290744221392610955845565494
    3708750229467761730471738895197792271346693089326102132000338192
    0131874187833985420922688804220167840319199699494193852403223700
    5853832741544191628747052136402176941963825543565900589161585723
    4023097417605004829991929283045372355639145644588174733401360176
    9953973706537274133283614740902771561159913069917833820285608440
    3104966899999651928637634656418969027076699082888742481392304807
    9484725489080844360397606199771786024695620205344042765860581379
    3538290451208322129898069978107971226873160872046731879753034549
    3130492167474809196348846916421782850086985668680640425192038155
    4902863298351349469211627292865440876581064873866786120098602898
    8799130098877372097360065934827751120659213470528793143805903554
    7928682131082164366007016698761961066948371407368962539467994627
    1374858249110795976398595034606994740186040425117101588480000000
    0000000000000000000000000000000000000000000000000000000000000000
    00000000000000000000000000000000000000
    /
    2629990810403002651095959155503002285441272170673105334466808931
    6863103901346024240326549035084528682487048064823380723787110941
    6809235187356318780972302796570251102928552003708556939314795678
    1978390674393498540663747334079841518303636625888963910391440709
    0887345797303470959207883316838346973393937778363411195624313553
    8835644822353659840936818391050630360633734935381528275392050975
    7271468992840907541350345459011192466892177866882264242860412188
    0652112744642450404625763019639086944558899249788084559753723892
    1643188991444945360726899532023542969572584363761073528841147012
    2634218045463494055807073778490814692996517359952229262198396182
    1838930043528583109973872348193806830382584040536394640895148751
    0766256738740729894909630785260101721285704616818889741995949666
    6303289703199393801976334974240815397920213059799071915067856758
    6716458821062645562512745336709063396510021681900076680696945309
    3660590933279867736747926648678738515702777431353845466199680991
    73361873421152165477774911660108200059

The decimal expansion itself looks like this:

clp(q) ?- e(1000, E), print_decimal(E, 1000).
2.
7182818284 5904523536 0287471352 6624977572 4709369995 9574966967
6277240766 3035354759 4571382178 5251664274 2746639193 2003059921
8174135966 2904357290 0334295260 5956307381 3232862794 3490763233
8298807531 9525101901 1573834187 9307021540 8914993488 4167509244
7614606680 8226480016 8477411853 7423454424 3710753907 7744992069
5517027618 3860626133 1384583000 7520449338 2656029760 6737113200
7093287091 2744374704 7230696977 2093101416 9283681902 5515108657
4637721112 5238978442 5056953696 7707854499 6996794686 4454905987
9316368892 3009879312 7736178215 4249992295 7635148220 8269895193
6680331825 2886939849 6465105820 9392398294 8879332036 2509443117
3012381970 6841614039 7019837679 3206832823 7646480429 5311802328
7825098194 5581530175 6717361332 0698112509 9618188159 3041690351
5988885193 4580727386 6738589422 8792284998 9208680582 5749279610
4841984443 6346324496 8487560233 6248270419 7862320900 2160990235
3043699418 4914631409 3431738143 6405462531 5209618369 0888707016
7683964243 7814059271 4563549061 3031072085 1038375051 0115747704
1718986106 8739696552 1267154688 9570350354


Node:Projection, Next:, Previous:Numerical Precision, Up:CLPQR

Projection and Redundancy Elimination

Once a derivation succeeds, the Prolog system presents the bindings for the variables in the query. In a CLP system, the set of answer constraints is presented in analogy. A complication in the CLP context are variables and associated constraints that were not mentioned in the query. A motivating example is the familiar mortgage relation:

%
% from file: library('clpqr/examples/mg')
%
mg(P,T,I,B,MP):-
  {
     T = 1,
     B + MP = P * (1 + I)
  }.
mg(P,T,I,B,MP):-
  {
     T > 1,
     P1 = P * (1 + I) - MP,
     T1 = T - 1
  },
  mg(P1, T1, I, B, MP).
A sample query yields:
clp(r) ?- use_module(library('clpqr/examples/mg')).
clp(r) ?- mg(P,12,0.01,B,Mp).

{B=1.1268250301319698*P-12.682503013196973*Mp}
Without projection of the answer constraints onto the query variables we would observe the following interaction:
clp(r) ?- mg(P,12,0.01,B,Mp).

{B=12.682503013196973*_A-11.682503013196971*P},
{Mp= -(_A)+1.01*P},
{_B=2.01*_A-1.01*P},
{_C=3.0301*_A-2.0301*P},
{_D=4.060401000000001*_A-3.0604009999999997*P},
{_E=5.101005010000001*_A-4.10100501*P},
{_F=6.152015060100001*_A-5.152015060099999*P},
{_G=7.213535210701001*_A-6.213535210700999*P},
{_H=8.285670562808011*_A-7.285670562808009*P},
{_I=9.368527268436091*_A-8.36852726843609*P},
{_J=10.462212541120453*_A-9.46221254112045*P},
{_K=11.566834666531657*_A-10.566834666531655*P}
The variables _A ... _K are not part of the query, they originate from the mortgage program proper. Although the latter answer is equivalent to the former in terms of linear algebra, most users would prefer the former.


Node:Variable Ordering, Next:, Previous:Projection, Up:Projection

Variable Ordering

In general, there are many ways to express the same linear relationship between variables. clp(Q,R) does not care to distinguish between them, but the user might. The predicate ordering(+Spec) gives you some control over the variable ordering. Suppose that instead of B, you want Mp to be the defined variable:

clp(r) ?- mg(P,12,0.01,B,Mp).

{B=1.1268250301319698*P-12.682503013196973*Mp}
This is achieved with:
clp(r) ?-  mg(P,12,0.01,B,Mp), ordering([Mp]).

{Mp= -0.0788487886783417*B+0.08884878867834171*P}
One could go one step further and require P to appear before (to the left of) B in a addition:
clp(r) ?- mg(P,12,0.01,B,Mp), ordering([Mp,P]).

{Mp=0.08884878867834171*P-0.0788487886783417*B}

Spec in ordering(+Spec) is either a list of variables with the intended ordering, or of the form A<B. The latter form means that A goes to the left of B. In fact, ordering([A,B,C,D]) is shorthand for:

ordering(A < B), ordering(A < C), ordering(A < D),
ordering(B < C), ordering(B < D),
ordering(C < D)

The ordering specification only affects the final presentation of the constraints. For all other operations of clp(Q,R), the ordering is immaterial. Note that ordering/1 acts like a constraint: you can put it anywhere in the computation, and you can submit multiple specifications.

clp(r) ?- ordering(B < Mp), mg(P,12,0.01,B,Mp).

{B= -12.682503013196973*Mp+1.1268250301319698*P}

yes
clp(r) ?- ordering(B < Mp), mg(P,12,0.01,B,Mp), ordering(P < Mp).

{P=0.8874492252651537*B+11.255077473484631*Mp}


Node:Turning Answers into Terms, Next:, Previous:Variable Ordering, Up:Projection

Turning Answers into Terms

In meta-programming applications one needs to get a grip on the results computed by the clp(Q,R) solver. You can use the predicates dump/3 and/or call_residue/2 for that purpose:

clp(r) ?- {2*A+B+C=10,C-D=E,A<10}, dump([A,B,C,D,E],[a,b,c,d,e],Constraints).

Constraints = [e<10.0,a=10.0-c-d-2.0*e,b=c+d],
{C=10.0-2.0*A-B},
{E=10.0-2.0*A-B-D},
{A<10.0}
clp(r) ?- call_residue({2*A+B+C=10,C-D=E,A<10}, Constraints).

Constraints = [
               [A]-{A<10.0},
               [B]-{B=10.0-2.0*A-C},
               [D]-{D=C-E}
              ]


Node:Projecting Inequalities, Previous:Turning Answers into Terms, Up:Projection

Projecting Inequalities

As soon as linear inequations are involved, projection gets more demanding complexity wise. The current clp(Q,R) version uses a Fourier-Motzkin algorithm for the projection of linear inequalities. The choice of a suitable algorithm is somewhat dependent on the number of variables to be eliminated, the total number of variables, and other factors. It is quite easy to produce problems of moderate size where the elimination step takes some time. For example, when the dimension of the projection is 1, you might be better off computing the supremum and the infimum of the remaining variable instead of eliminating n-1 variables via implicit projection.

In order to make answers as concise as possible, redundant constraints are removed by the system as well. In the following set of inequalities, half of them are redundant.

%
% from file: library('clpqr/examples/eliminat')
%
example(2, [X0,X1,X2,X3,X4]) :-
  {
       +87*X0  +52*X1  +27*X2  -54*X3  +56*X4 =<  -93,
       +33*X0  -10*X1  +61*X2  -28*X3  -29*X4 =<   63,
       -68*X0   +8*X1  +35*X2  +68*X3  +35*X4 =<  -85,
       +90*X0  +60*X1  -76*X2  -53*X3  +24*X4 =<  -68,
       -95*X0  -10*X1  +64*X2  +76*X3  -24*X4 =<   33,
       +43*X0  -22*X1  +67*X2  -68*X3  -92*X4 =<  -97,
       +39*X0   +7*X1  +62*X2  +54*X3  -26*X4 =<  -27,
       +48*X0  -13*X1   +7*X2  -61*X3  -59*X4 =<   -2,
       +49*X0  -23*X1  -31*X2  -76*X3  +27*X4 =<    3,
       -50*X0  +58*X1   -1*X2  +57*X3  +20*X4 =<    6,
       -13*X0  -63*X1  +81*X2   -3*X3  +70*X4 =<   64,
       +20*X0  +67*X1  -23*X2  -41*X3  -66*X4 =<   52,
       -81*X0  -44*X1  +19*X2  -22*X3  -73*X4 =<  -17,
       -43*X0   -9*X1  +14*X2  +27*X3  +40*X4 =<   39,
       +16*X0  +83*X1  +89*X2  +25*X3  +55*X4 =<   36,
        +2*X0  +40*X1  +65*X2  +59*X3  -32*X4 =<   13,
       -65*X0  -11*X1  +10*X2  -13*X3  +91*X4 =<   49,
       +93*X0  -73*X1  +91*X2   -1*X3  +23*X4 =<  -87
  }.
Consequently, the answer consists of the system of nine non-redundant inequalities only:
clp(q) ?- use_module(library('clpqr/examples/elimination')).
clp(q) ?- example(2, [X0,X1,X2,X3,X4]).

{X0-2/17*X1-35/68*X2-X3-35/68*X4>=5/4},
{X0-73/93*X1+91/93*X2-1/93*X3+23/93*X4=<-29/31},
{X0-29/25*X1+1/50*X2-57/50*X3-2/5*X4>=-3/25},
{X0+7/39*X1+62/39*X2+18/13*X3-2/3*X4=<-9/13},
{X0+2/19*X1-64/95*X2-4/5*X3+24/95*X4>=-33/95},
{X0+2/3*X1-38/45*X2-53/90*X3+4/15*X4=<-34/45},
{X0-23/49*X1-31/49*X2-76/49*X3+27/49*X4=<3/49},
{X0+44/81*X1-19/81*X2+22/81*X3+73/81*X4>=17/81},
{X0+9/43*X1-14/43*X2-27/43*X3-40/43*X4>=-39/43}

The projection (the shadow) of this polyhedral set into the X0,X1 space can be computed via the implicit elimination of non-query variables:

clp(q) ?- example(2, [X0,X1|_]).

{X0+2619277/17854273*X1>=-851123/17854273},
{X0+6429953/16575801*X1=<-12749681/16575801},
{X0+19130/1213083*X1>=795400/404361},
{X0-1251619/3956679*X1>=21101146/3956679},
{X0+601502/4257189*X1>=220850/473021}

Projection is quite a powerful concept that leads to surprisingly terse executable specifications of nontrivial problems like the computation of the convex hull from a set of points in an n-dimensional space: Given the program

%
% from file: library('clpqr/examples/elimination')
%
conv_hull(Points, Xs) :-
  lin_comb(Points, Lambdas, Zero, Xs),
  zero(Zero),
  polytope(Lambdas).

polytope(Xs) :-
  positive_sum(Xs, 1).

  positive_sum([], Z) :- {Z=0}.
  positive_sum([X|Xs], SumX) :-
    { X >= 0, SumX = X+Sum },
    positive_sum(Xs, Sum).

zero([]).
zero([Z|Zs]) :- {Z=0}, zero(Zs).

lin_comb([],        [],     S1, S1).
lin_comb([Ps|Rest], [K|Ks], S1, S3) :-
  lin_comb_r(Ps, K, S1, S2),
  lin_comb(Rest, Ks, S2, S3).

  lin_comb_r([],     _, [],     []).
  lin_comb_r([P|Ps], K, [S|Ss], [Kps|Ss1]) :-
    { Kps = K*P+S },
    lin_comb_r(Ps, K, Ss, Ss1).
we can post the following query:
clp(q) ?- conv_hull([ [1,1], [2,0], [3,0], [1,2], [2,2] ], [X,Y]).

{Y=<2},
{X+1/2*Y=<3},
{X>=1},
{Y>=0},
{X+Y>=2}
This answer is easily verified graphically:
       |
     2 -    *    *
       |
       |
     1 -    *
       |
       |
     0 -----|----*----*----
            1    2    3
The convex hull program directly corresponds to the mathematical definition of the convex hull. What does the trick in operational terms is the implicit elimination of the Lambdas from the program formulation. Please note that this program does not limit the number of points or the dimension of the space they are from. Please note further that quantifier elimination is a computationally expensive operation and therefore this program is only useful as a benchmark for the projector and not so for the intended purpose.


Node:Why Disequations, Next:, Previous:Projection, Up:CLPQR

Why Disequations

A beautiful example of disequations at work is due to [Colmerauer 90]. It addresses the task of tiling a rectangle with squares of all-different, a priori unknown sizes. Here is a translation of the original Prolog-III program to clp(Q,R):

%
% from file: library('clpqr/examples/squares')
%
filled_rectangle(A, C) :-
  { A >= 1 },
  distinct_squares(C),
  filled_zone([-1,A,1], _, C, []).

distinct_squares([]).
distinct_squares([B|C]) :-
  { B > 0 },
  outof(C, B),
  distinct_squares(C).

outof([],     _).
outof([B1|C], B) :-
  { B =\= B1 },       % *** note disequation ***
  outof(C, B).

filled_zone([V|L], [W|L], C0, C0) :-
  { V=W,V >= 0 }.
filled_zone([V|L], L3, [B|C], C2) :-
  { V < 0 },
  placed_square(B, L, L1),
  filled_zone(L1, L2, C, C1),
  { Vb=V+B },
  filled_zone([Vb,B|L2], L3, C1, C2).

placed_square(B, [H,H0,H1|L], L1) :-
  { B > H, H0=0, H2=H+H1 },
  placed_square(B, [H2|L], L1).
placed_square(B, [B,V|L], [X|L]) :-
  { X=V-B }.
placed_square(B, [H|L], [X,Y|L]) :-
  { B < H, X= -B, Y=H-B }.
There are no tilings with less than nine squares except the trivial one where the rectangle equals the only square. There are eight solutions for nine squares. Six further solutions are rotations of the first two.
clp(q) ?- use_module(library('clpqr/examples/squares')).
clp(q) ?- filled_rectangle(A, Squares).

A = 1,
Squares = [1] ? ;

A = 33/32,
Squares = [15/32,9/16,1/4,7/32,1/8,7/16,1/32,5/16,9/32] ? ;

A = 69/61,
Squares = [33/61,36/61,28/61,5/61,2/61,9/61,25/61,7/61,16/61]

Depending on your hardware, the above query may take a few minutes. Supplying the knowledge about the minimal number of squares beforehand cuts the computation time by a factor of roughly four:

clp(q) ?- length(Squares, 9), filled_rectangle(A, Squares).

A = 33/32,
Squares = [15/32,9/16,1/4,7/32,1/8,7/16,1/32,5/16,9/32] ? ;

A = 69/61,
Squares = [33/61,36/61,28/61,5/61,2/61,9/61,25/61,7/61,16/61]


Node:Syntactic Sugar, Next:, Previous:Why Disequations, Up:CLPQR

Syntactic Sugar

There is a package that transforms programs and queries from a eval-quote variant of clp(Q,R) into corresponding programs and queries in a quote-eval variant. Before you use it, you need to know that in an eval-quote language, all symbols are interpreted unless explicitly quoted. This means that interpreted terms cannot be manipulated syntactically directly. Meta-programming in a CLP context by definition manipulates interpreted terms, therefore you need quote/1 (just as in LISP) and some means to put syntactical terms back to their interpreted life: {}/1.

In a quote-eval language, meta-programming is (pragmatically) simpler because everything is implicitly quoted until explicitly evaluated. On the other hand, now object programming suffers from the dual inconvenience.

We chose to make our version of clp(Q,R) of the quote-eval type because this matches the intended use of the already existing boolean solver of SICStus. In order to keep the users of the eval-quote variant happy, we provide a source transformation package. It is activated via:

| ?- use_module(library('clpqr/expand')).
Loading the package puts you in a mode where the arithmetic functors like +/2, */2 and all numbers (functors of arity 0) are interpreted semantically.
clp(r) ?- 2+2=X.

X = 4.0
The package works by purifying programs and queries in the sense that all references to interpreted terms are made explicit. The above query is expanded prior to evaluation into:
{2.0+2.0=X}
The same mechanism applies when interpreted terms are nested deeper:
some_predicate(10, f(A+B/2), 2*cos(A))
Expands into:
{Xc=2.0*cos(A)},
{Xb=A+B/2},
{Xa=10.0},
some_predicate(Xa, f(Xb), Xc)
This process also applies when files are consulted or compiled. In fact, this is the only situation where expansion can be applied with relative safety. To see this, consider what happens when the top level evaluates the expansion, namely some calls to the clp(Q,R) solver, followed by the call of the purified query. As we learned in Feedback, the solver may bind variables, which produces a goal with interpreted functors in it (numbers), which leads to another stage of expansion, and so on.

We recommend that you only turn on expansion temporarily while consulting or compiling files needing expansion with expand/0 and noexpand/0.


Node:Monash Examples, Previous:Syntactic Sugar, Up:Syntactic Sugar

Monash Examples

This collection of examples has been distributed with the Monash University Version of clp(R) [Heintze et al. 87], and its inclusion into this distribution was kindly permitted by Roland Yap.

In order to execute the examples, a small compatibility package has to be loaded first:

clp(r) ?- use_module(library('clpqr/monash')).
Then, assuming you are using clp(R):
clp(r) ?- expand, [library('clpqr/examples/monash/rkf45')],
          noexpand.

clp(r) ?- go.
Point    0.00000 :    0.75000    0.00000
Point    0.50000 :    0.61969    0.47793
Point    1.00000 :    0.29417    0.81233
Point    1.50000 :   -0.10556    0.95809
Point    2.00000 :   -0.49076    0.93977
Point    2.50000 :   -0.81440    0.79929
Point    3.00000 :   -1.05440    0.57522

Iteration finished
------------------
 439  derivative evaluations


Node:Compatibility Notes, Previous:Monash Examples, Up:Monash Examples

Compatibility Notes

The Monash examples have been written for clp(R). Nevertheless, all but rkf45 complete nicely in clp(Q). With rkf45, clp(Q) runs out of memory. This is an instance of the problem discussed in Numerical Precision.

The Monash University clp(R) interpreter features a dump/n predicate. It is used to print the target variables according to the given ordering. Within this version of clp(Q,R), the corresponding functionality is provided via ordering/1. The difference is that ordering/1 does only specify the ordering of the variables and no printing is performed. We think Prolog has enough predicates to perform output already. You can still run the examples referring to dump/n from the Prolog top level:

clp(r) ?- expand, [library('clpqr/examples/monash/mortgage')], noexpand.

% go2
%
clp(r) ?- mg(P,120,0.01,0,MP), dump([P,MP]).

{P=69.7005220313972*MP}

% go3
%
clp(r) ?- mg(P,120,0.01,B,MP), dump([P,B,MP]).

{P=0.30299477968602706*B+69.7005220313972*MP}

% go4
%
clp(r) ?- mg(999, 3, Int, 0, 400), dump.

clpr:{_B-_B*Int+_A+400.0=0.0},
clpr:{_A-_A*Int+400.0=0.0},
{_B=599.0+999.0*Int}


Node:MIP, Next:, Previous:Syntactic Sugar, Up:CLPQR

A Mixed Integer Linear Optimization Example

The predicates bb_inf/3, bb_inf/5 implement a simple Branch and Bound search algorithm for Mixed Integer Linear (MIP) Optimization examples. Serious MIP is not trivial. The implementation library('clpqr/bb.pl') is to be understood as a starting point for more ambitious users who need control over branching, or who want to add cutting planes, for example.

Anyway, here is a small problem from miplib, a collection of MIP models, housed at Rice University:

NAME:         flugpl
ROWS:         18
COLUMNS:      18
INTEGER:      11
NONZERO:      46
BEST SOLN:    1201500 (opt)
LP SOLN:      1167185.73
SOURCE:       Harvey M. Wagner
              John W. Gregory (Cray Research)
              E. Andrew Boyd (Rice University)
APPLICATION:  airline model
COMMENTS:     no integer variables are binary
%
% from file: library('clpqr/examples/mip')
%
example(flugpl, Obj, Vs, Ints, []) :-
  Vs = [ Anm1,Anm2,Anm3,Anm4,Anm5,Anm6,
         Stm1,Stm2,Stm3,Stm4,Stm5,Stm6,
         UE1,UE2,UE3,UE4,UE5,UE6],
  Ints = [Stm6, Stm5, Stm4, Stm3, Stm2,
          Anm6, Anm5, Anm4, Anm3, Anm2, Anm1],

  Obj =    2700*Stm1 + 1500*Anm1 + 30*UE1
         + 2700*Stm2 + 1500*Anm2 + 30*UE2
         + 2700*Stm3 + 1500*Anm3 + 30*UE3
         + 2700*Stm4 + 1500*Anm4 + 30*UE4
         + 2700*Stm5 + 1500*Anm5 + 30*UE5
         + 2700*Stm6 + 1500*Anm6 + 30*UE6,

  allpos(Vs),
  {  Stm1 = 60, 0.9*Stm1 +1*Anm1 -1*Stm2 = 0,
     0.9*Stm2 +1*Anm2 -1*Stm3 = 0, 0.9*Stm3 +1*Anm3 -1*Stm4 = 0,
     0.9*Stm4 +1*Anm4 -1*Stm5 = 0, 0.9*Stm5 +1*Anm5 -1*Stm6 = 0,
     150*Stm1 -100*Anm1 +1*UE1 >= 8000,
     150*Stm2 -100*Anm2 +1*UE2 >= 9000,
     150*Stm3 -100*Anm3 +1*UE3 >= 8000,
     150*Stm4 -100*Anm4 +1*UE4 >= 10000,
     150*Stm5 -100*Anm5 +1*UE5 >= 9000,
     150*Stm6 -100*Anm6 +1*UE6 >= 12000,
     -20*Stm1 +1*UE1 =< 0, -20*Stm2 +1*UE2 =< 0, -20*Stm3 +1*UE3 =< 0,
     -20*Stm4 +1*UE4 =< 0, -20*Stm5 +1*UE5 =< 0, -20*Stm6 +1*UE6 =< 0,
     Anm1 =< 18, 57 =< Stm2, Stm2 =< 75, Anm2 =< 18,
     57 =< Stm3, Stm3 =< 75, Anm3 =< 18, 57 =< Stm4,
     Stm4 =< 75, Anm4 =< 18, 57 =< Stm5, Stm5 =< 75,
     Anm5 =< 18, 57 =< Stm6, Stm6 =< 75, Anm6 =< 18
   }.

  allpos([]).
  allpos([X|Xs]) :- {X >= 0}, allpos(Xs).

We can first check whether the relaxed problem has indeed the quoted infimum:

clp(r) ?- example(flugpl, Obj, _, _, _), inf(Obj, Inf).

Inf = 1167185.7255923203

Computing the infimum under the additional constraints that Stm6, Stm5, Stm4, Stm3, Stm2, Anm6, Anm5, Anm4, Anm3, Anm2, Anm1 assume integer values at the infimum is computationally harder, but the query does not change much:

clp(r) ?- example(flugpl, Obj, _, Ints, _),
          bb_inf(Ints, Obj, Inf, Vertex, 0.001).

Inf = 1201500.0000000005,
Vertex = [75.0,70.0,70.0,60.0,60.0,0.0,12.0,7.0,16.0,6.0,6.0]


Node:Implementation Architecture, Previous:MIP, Up:CLPQR

Implementation Architecture

The system consists roughly of the following components:


Node:Fragments and Bits, Next:, Previous:Implementation Architecture, Up:Implementation Architecture

Fragments and Bits


Node:Rationals, Next:, Previous:Fragments and Bits, Up:Fragments and Bits

Rationals

The internal data structure for rational numbers is rat(Num,Den). Den is always positive, i.e. the sign of the rational number is the sign of Num. Further, Num and Den are relative prime. Note that integer N looks like rat(N,1) in this representation. You can control printing of terms with portray/1.


Node:Partial Evaluation, Next:, Previous:Rationals, Up:Fragments and Bits

Partial Evaluation, Compilation

Once one has a working solver, it is obvious and attractive to run the constraints in a clause definition at read time or compile time and proceed with the answer constraints in place of the original constraints. This gets you constant folding and in fact the full algebraic power of the solver applied to the avoidance of computations at runtime. The mechanism to realize this idea is to use dump/3, call_residue/2 for the expansion of {}/1, via hook predicate user:goal_expansion/3).


Node:Asserting with Constraints, Previous:Partial Evaluation, Up:Fragments and Bits

Asserting with Constraints

If you use the dynamic data base, the clauses you assert might have constraints on the variables occurring in the clause. This works as expected:

clp(r) ?- {A < 10}, assert(p(A)).

{A<10.0}

yes
clp(r) ?- p(X).

{X<10.0}


Node:Bugs, Previous:Fragments and Bits, Up:Implementation Architecture

Bugs

Please send bug reports to <christian@ai.univie.ac.at>.


Node:CLPFD, Next:, Previous:CLPQR, Up:Top

Constraint Logic Programming over Finite Domains


Node:CLPFD Intro, Next:, Previous:CLPFD, Up:CLPFD

Introduction

The clp(FD) solver described in this chapter is an instance of the general Constraint Logic Programming scheme introduced in [Jaffar & Michaylov 87]. This constraint domain is particularly useful for modeling discrete optimization and verification problems such as scheduling, planning, packing, timetabling etc. The treatise [Van Hentenryck 89] is an excellent exposition of the theoretical and practical framework behind constraint solving in finite domains, and summarizes the work up to 1989.

This solver has the following highlights:

The rest of this chapter is organized as follows: How to load the solver and how to write simple programs is explained in CLPFD Interface. A description of all constraints that the solver provides is contained in Available Constraints. The predicates for searching for solution are documented in Enumeration Predicates. The predicates for getting execution statistics are documented in Statistics Predicates. A few example programs are given in Example Programs. Finally, Syntax Summary contains syntax rules for all expressions.

The following sections discuss advanced features and are probably only relevant to experienced users: How to control the amount of information presented in answers to queries is explained in Answer Constraints. The solver's execution mechanism and primitives are described in The Constraint System. How to add new global constraints via a programming interface is described in Defining Global Constraints. How to define new primitive constraints with indexicals is described in Defining Primitive Constraints.


Node:Referencing CLPFD, Next:, Previous:CLPFD Intro, Up:CLPFD Intro

Referencing this Software

When referring to this implementation of clp(FD) in publications, please use the following reference:

Carlsson M., Ottosson G., Carlson B. "An Open-Ended Finite Domain Constraint Solver" Proc. Programming Languages: Implementations, Logics, and Programs, 1997.


Node:Acknowledgments CLPFD, Previous:Referencing CLPFD, Up:CLPFD Intro

Acknowledgments

The first version of this solver was written as part of Key Hyckenberg's MSc thesis in 1995, with contributions from Greger Ottosson at the Computing Science Department, Uppsala University. The code was later rewritten by Mats Carlsson. Peter Szeredi contributed material for this manual chapter.

The development of this software was supported by the Swedish National Board for Technical and Industrial Development (NUTEK) under the auspices of Advanced Software Technology (ASTEC) Center of Competence at Uppsala University.

We include a collection of examples, some of which have been distributed with the INRIA implementation of clp(FD) [Diaz & Codognet 93].


Node:CLPFD Interface, Next:, Previous:CLPFD Intro, Up:CLPFD

Solver Interface

The solver is available as a library module and can be loaded with a query

:- use_module(library(clpfd)).

The solver contains predicates for checking the consistency and entailment of finite domain constraints, as well as solving for solution values for your problem variables.

In the context of this constraint solver, a finite domain is a subset of the integers, and a finite domain constraint denotes a relation over one or more finite domains. All domain variables, i.e. variables that occur as arguments to finite domain constraints get associated with a finite domain, either explicitly declared by the program, or implicitly imposed by the constraint solver. Temporarily, the domain of a variable may actually be infinite, if it does not have a finite lower or upper bound.

The domain of all variables gets narrower and narrower as more constraints are added. If a domain becomes empty, the accumulated constraints are unsatisfiable, and the current computation branch fails. At the end of a successful computation, all domains have usually become singletons, i.e. the domain variables have become assigned.

The domains do not become singletons automatically. Usually, it takes some amount of search to find an assignment that satisfies all constraints. It is the programmer's responsibility to do so. If some domain variables are left unassigned in a computation, the garbage collector will preserve all constraint data that is attached to them. Furthermore, the behavior of the predicates assert/1, findall/3, copy_term/2 and friends is undefined on non-ground terms containing domain variables.

The heart of the constraint solver is a scheduler for indexicals [Van Hentenryck et al. 92] and global constraints. Both entities act as coroutines performing incremental constraint solving or entailment checking. They wake up by changes in the domains of its arguments. All constraints provided by this package are implemented as indexicals or global constraints. New constraints can be defined by the user.

Indexicals are reactive functional rules that take part in the solver's basic constraint solving algorithm, whereas each global constraint is associated with its particular constraint solving algorithm. The solver maintains two scheduling queues, giving priority to the queue of indexicals.

The feasibility of integrating the indexical approach with a Prolog based on the WAM was clearly demonstrated by Diaz's clp(FD) implementation [Diaz & Codognet 93], one of the fastest finite domains solvers around.


Node:Posting Constraints, Next:, Previous:CLPFD Interface, Up:CLPFD Interface

Posting Constraints

A constraint is called as any other Prolog predicate. When called, the constraint is posted to the store. For example:

| ?- X in 1..5, Y in 2..8, X+Y #= T.

X in 1..5,
Y in 2..8,
T in 3..13 ?

yes
| ?- X in 1..5, T in 3..13, X+Y #= T.

X in 1..5,
T in 3..13,
Y in -2..12 ?

yes

Note that the answer constraint shows the domains of nonground query variables, but not any constraints that may be attached to them.


Node:A Constraint Satisfaction Problem, Next:, Previous:Posting Constraints, Up:CLPFD Interface

A Constraint Satisfaction Problem

Constraint satisfaction problems (CSPs) are a major class of problems for which this solver is ideally suited. In a CSP, the goal is to pick values from pre-defined domains for certain variables so that the given constraints on the variables are all satisfied.

As a simple CSP example, let us consider the Send More Money puzzle. In this problem, the variables are the letters S, E, N, D, M, O, R, and Y. Each letter represents a digit between 0 and 9. The problem is to assign a value to each digit, such that SEND + MORE equals MONEY.

A program which solves the puzzle is given below. The program contains the typical three steps of a clp(FD) program:

  1. declare the domains of the variables
  2. post the problem constraints
  3. look for a feasible solution via backtrack search, or look for an optimal solution via branch-and-bound search

Sometimes, an extra step precedes the search for a solution: the posting of surrogate constraints to break symmetries or to otherwise help prune the search space. No surrogate constraints are used in this example.

The domains of this puzzle are stated via the domain/3 goal and by requiring that S and M be greater than zero. The two problem constraint of this puzzle are the equation (sum/8) and the constraint that all letters take distinct values (all_different/1). Finally, the backtrack search is performed by labeling/2. Different search strategies can be encoded in the Type parameter. In the example query, the default search strategy is used (select the leftmost variable, try values in ascending order).

:- use_module(library(clpfd)).

mm([S,E,N,D,M,O,R,Y], Type) :-
     domain([S,E,N,D,M,O,R,Y], 0, 9),      % step 1
     S#>0, M#>0,
     all_different([S,E,N,D,M,O,R,Y]),     % step 2
     sum(S,E,N,D,M,O,R,Y),
     labeling(Type, [S,E,N,D,M,O,R,Y]).    % step 3

sum(S, E, N, D, M, O, R, Y) :-
                  1000*S + 100*E + 10*N + D
     +            1000*M + 100*O + 10*R + E
     #= 10000*M + 1000*O + 100*N + 10*E + Y.

| ?- mm([S,E,N,D,M,O,R,Y], []).

D = 7,
E = 5,
M = 1,
N = 6,
O = 0,
R = 8,
S = 9,
Y = 2 ?


Node:Reified Constraints, Previous:A Constraint Satisfaction Problem, Up:CLPFD Interface

Reified Constraints

Instead of merely posting constraints it is often useful to reflect its truth value into a 0/1-variable B, so that:

This mechanism is known as reification. Several frequently used operations can be defined in terms of reified constraints, such as blocking implication [Saraswat 90] and the cardinality operator [Van Hentenryck & Deville 91], to name a few. A reified constraint is written:

| ?- Constraint #<=> B.

where Constraint is reifiable. As an example of a constraint that uses reification, consider exactly(X,L,N) which is true if X occurs exactly N times in the list L. It can be defined thus:

exactly(_, [], 0).
exactly(X, [Y|L], N) :-
    X #= Y #<=> B,
    N #= M+B,
    exactly(X, L, M).


Node:Available Constraints, Next:, Previous:CLPFD Interface, Up:CLPFD

Available Constraints

This section describes the classes of constraints that can be used with this solver.


Node:Arithmetic Constraints, Next:, Previous:Available Constraints, Up:Available Constraints

Arithmetic Constraints

?Expr RelOp ?Expr

defines an arithmetic constraint. The syntax for Expr and RelOp is defined by a grammar (see Syntax of Arithmetic Expressions). Note that the expressions are not restricted to being linear. Constraints over non-linear expressions, however, will usually yield less constraint propagation than constraints over linear expressions. Any variables occurring in the expression must be unbound or bound to integers at run time.

Arithmetic constraints can be reified as e.g.

| ?- X in 1..2, Y in 3..5, X#=<Y #<=> B.

B = 1,
X in 1..2,
Y in 3..5 ?

Linear arithmetic constraints maintain (at least) interval-consistency and their reified versions detect (at least) interval-entailment and -disentailment; see The Constraint System.

The following constraints are among the library constraints that general arithmetic constraints compile to. They express a relation between a sum or a scalar product and a value, using a dedicated algorithm that avoids creating any temporary variables holding intermediate values. If you are computing a sum or a scalar product, it can be much more efficient to compute lists of coefficients and variables and post a single sum or scalar product constraint than to post a sequence of elementary constraints.

sum(+Xs, +RelOp, ?Value)

where Xs is a list of integers or domain variables, RelOp is a relational symbol as above, and Value is an integer or a domain variable. True if Xs RelOp Value. Cannot be reified.

scalar_product(+Coeffs, +Xs, +RelOp, ?Value)

where Coeffs is a list of length n of integers, Xs is a list of length n of integers or domain variables, RelOp is a relational symbol as above, and Value is an integer or a domain variable. True if Coeffs*Xs RelOp Value. Cannot be reified.


Node:Membership Constraints, Next:, Previous:Arithmetic Constraints, Up:Available Constraints

Membership Constraints

domain(+Variables, +Min, +Max)

where Variables is a list of domain variables or integers, Min is an integer or the atom inf (minus infinity), and Max is an integer or the atom sup (plus infinity). True if the variables all are elements of the range Min..Max. Cannot be reified.

?X in +Range

defines a membership constraint. X is an integer or a domain variable and Range is a ConstantRange (see Syntax of Indexicals). True if X is an element of the range.

?X in_set +FDSet

defines a membership constraint. X is an integer or a domain variable and FDSet is an FD set term (see FD Set Operations). True if X is an element of the FD set.

in/2 and in_set/2 constraints can be reified. They maintain domain-consistency and their reified versions detect domain-entailment and -disentailment; see The Constraint System.


Node:Propositional Constraints, Next:, Previous:Membership Constraints, Up:Available Constraints

Propositional Constraints

Propositional combinators can be used to combine reifiable constraints into propositional formulae over such constraints. Such formulae are goal expanded by the system into sequences of reified constraints and arithmetic constraints. For example,

X #= 4 #\/ Y #= 6

expresses the disjunction of two equality constraints.

The leaves of propositional formulae can be reifiable constraints, the constants 0 and 1, or 0/1-variables. New primitive, reifiable constraints can be defined with indexicals as described in Defining Primitive Constraints. The following propositional combinators are available:

#\ :Q

True if the constraint Q is false.

:P #/\ :Q

True if the constraints P and Q are both true.

:P #\ :Q

True if exactly one of the constraints P and Q is true.

:P #\/ :Q

True if at least one of the constraints P and Q is true.

:P #=> :Q
:Q #<= :P

True if the constraint Q is true or the constraint P is false.

:P #<=> :Q

True if the constraints P and Q are both true or both false.

Note that the reification scheme introduced in Reified Constraints is a special case of a propositional constraint.


Node:Combinatorial Constraints, Next:, Previous:Propositional Constraints, Up:Available Constraints

Combinatorial Constraints

The constraints listed here are sometimes called symbolic constraints. They are currently not reifiable.

count(+Val,+List,+RelOp,?Count)

where Val is an integer, List is a list of integers or domain variables, Count an integer or a domain variable, and RelOp is a relational symbol as in Arithmetic Constraints. True if N is the number of elements of List that are equal to Val and N RelOp Count. Thus, count/4 is a generalization of exactly/3 (not an exported constraint) that was used in an example earlier.

count/4 maintains domain-consistency; see The Constraint System.

element(?X,+List,?Y)

where X and Y are integers or domain variables and List is a list of integers or domain variables. True if the X:th element of List is Y. Operationally, the domains of X and Y are constrained so that for every element in the domain of X, there is a compatible element in the domain of Y, and vice versa.

This constraint uses an optimized algorithm for the special case where List is ground.

element/3 maintains domain-consistency in X and interval-consistency in List and Y; see The Constraint System.

relation(?X,+MapList,?Y)

where X and Y are integers or domain variables and MapList is a list of integer-ConstantRange pairs, where the integer keys occur uniquely (see Syntax of Indexicals). True if MapList contains a pair X-R and Y is in the range denoted by R.

Operationally, the domains of X and Y are constrained so that for every element in the domain of X, there is a compatible element in the domain of Y, and vice versa.

If MapList is not ground, the constraint must be wrapped in call/1 to postpone goal expansion until runtime.

An arbitrary binary constraint can be defined with relation/3. relation/3 maintains domain-consistency; see The Constraint System.

all_different(+Variables)
all_different(+Variables, +Options)
all_distinct(+Variables)
all_distinct(+Variables, +Options)

where Variables is a list of domain variables or integers. Each variable is constrained to take a value that is unique among the variables. Declaratively, this is equivalent to an inequality constraint for each pair of variables.

Options is a list of zero or more of the following, where Boolean must be true or false (false is the default):

on(On)
How eagerly to wake up the constraint. One of value (the default for all_different/[1,2]), to wake up when a variable becomes ground; range, to wake up when a bound of a variable is changed; or domain (the default for all_distinct/[1,2]), to wake up when the domain of a variable is changed.
complete(Boolean)
Which algorithm to use. If true (the default for all_distinct/[1,2]), a complete algorithm [Regin 94] is used, i.e. it maintains domain-consistency. Otherwise (the default for all_different/[1,2]), an incomplete one is used, achieving exactly the same pruning as a set of pairwise inequality constraints.

The following is a constraint over two lists of length n of variables. Each variable is constrained to take a value in 1,...,n that is unique for its list. Furthermore, the lists are dual in a sense described below.

assignment(+Xs, +Ys)
assignment(+Xs, +Ys, +Options)

where Xs and Ys are lists of domain variables or integers, both of length n. Options is a list of the same form as in all_different/2 with the default value [on(domain),complete(true)]. True if all Xi, Yi in 1,...,n and Xi=j iff Yj=i.

The following constraint can be thought of as constraining n nodes in a graph to form a Hamiltonian circuit. The nodes are numbered from 1 to n. The circuit starts in node 1, visits each node, and returns to the origin.

circuit(+Succ)
circuit(+Succ, +Pred)

where Succ is a list of length n of domain variables or integers. The i:th element of Succ (Pred) is the successor (predecessor) of i in the graph. True if the values form a Hamiltonian circuit.

The following four constraints can be thought of as constraining n tasks, each with a start time Sj and a duration Dj, so that no tasks ever overlap. The tasks can be seen as competing for some exclusive resource.

serialized(+Starts,+Durations)
serialized(+Starts,+Durations,+Options)

where Starts = [S1,...,Sn] and Durations = [D1,...,Dn] are lists of domain variables with finite bounds or integers. Durations must be non-negative. True if Starts and Durations denote a set of non-overlapping tasks, i.e.:

Si+Di =< Sj OR Sj+Dj =< Si, for all 1 =< i<j =< n

The serialized/[2,3] constraint is merely a special case of cumulative/[4,5] (see below).

Options is a list of zero or more of the following, where Boolean must be true or false (false is the default):

precedences(Ps)
Ps encodes a set of precedence constraint to apply to the tasks. Ps should be a list of terms of the form d(i,j,d), where i and j should be task numbers, and d should be a positive integer or sup. Each term adds the constraint:
Si+d =< Sj OR Sj =< Si, if d is an integer
Sj =< Si, if d is sup

resource(R)
R is unified with a term which can be passed to order_resource/2 (see Enumeration Predicates) in order to find a consistent ordering of the tasks.
path_consistency(Boolean)
if true, a redundant path consistency algorithm will be used inside the constraint in an attempt to improve the pruning.
static_sets(Boolean)
if true, a redundant algorithm will be used which reasons about the set of tasks that must precede (be preceded by) a given task, in an attempt to tighten the lower (upper) bound of a given start variable.
edge_finder(Boolean)
if true, a redundant algorithm will be used which attempts to identify tasks that necessarily precede or are preceded by some set of tasks.
decomposition(Boolean)
if true, an attempt is made to decompose the constraint each time it is resumed.

Whether it's worthwhile to switch on any of the latter four options is highly problem dependent.

serialized/3 can model a set of tasks to be serialized with sequence-dependent setup times. For example, the following constraint models three tasks, all with duration 5, where task 1 must precede task 2 and task 3 must either complete before task 2 or start at least 10 time units after task 2 started:

?- domain([S1,S2,S3], 0, 20),
   serialized([S1,S2,S3], [5,5,5], [precedences([d(2,1,sup),d(2,3,10)])]).

S1 in 0..15,
S2 in 5..20,
S3 in 0..20 ?

The bounds of S1 and S2 changed because of the precedence constraint. Setting S2 to 5 will propagate S1=0 and S3 in 15..20.

The following constraint can be thought of as constraining n tasks, each with a start time Sj, a duration Dj, and a resource amount Rj, so that the total resource consumption does not exceed Limit at any time:

cumulative(+Starts,+Durations,+Resources,?Limit)
cumulative(+Starts,+Durations,+Resources,?Limit,+Options)

where Starts = [S1,...,Sn], Durations = [D1,...,Dn], Resource = [R1,...,Rn] are lists of domain variables with finite bounds or integers, and Limit is a domain variable with finite bounds or an integer. Durations, Resources and Limit must be non-negative. Let:

a = min(S1,...,Sn),
b = max(S1+D1,...,Sn+Dn)
Rij = Rj, if Sj =< i < Sj+Dj
Rij = 0 otherwise

The constraint holds if:

Ri1+...+Rin =< Limit, for all a =< i < b

If given, Options should be of the same form as in serialized/3, except the resource(R) option is not useful in cumulative/5.

The cumulative/4 constraint is due to Aggoun and Beldiceanu [Aggoun & Beldiceanu 93]. The algorithm is incomplete.


Node:User-Defined Constraints, Previous:Combinatorial Constraints, Up:Available Constraints

User-Defined Constraints

New, primitive constraints can be added defined by the user on two different levels. On a higher level, constraints can be defined using the global constraint programming interface; see Defining Global Constraints. Such constraints can embody specialized algorithms and use the full power of Prolog. They cannot be reified.

On a lower level, new primitive constraints can be defined with indexicals. In this case, they take part in the basic constraint solving algorithm and express custom designed rules for special cases of the overall local propagation scheme. Such constraints are called FD predicates; see Defining Primitive Constraints. They can optionally be reified.


Node:Enumeration Predicates, Next:, Previous:Available Constraints, Up:CLPFD

Enumeration Predicates

As is usually the case with finite domain constraint solvers, this solver is not complete. That is, it does not ensure that the set of posted constraints is satisfiable. One must resort to search (enumeration) to check satisfiability and get particular solutions.

The following predicates provide several variants of search:

indomain(?X)

where X is a domain variable with a bounded domain or an integer. Assigns, in increasing order via backtracking, a feasible value to X.

labeling(:Options, +Variables)

where Variables is a list of domain variables or integers and Options is a list of search options. The domain variables must all have bounded domains. True if an assignment of the variables can be found which satisfies the posted constraints.

apply_bound(BB)

Provides an auxiliary service for the value(Enum) option (see below).

minimize(:Goal,?X)
maximize(:Goal,?X)

Uses a branch-and-bound algorithm with restart to find an assignment that minimizes (maximizes) the domain variable X. Goal should be a Prolog goal that constrains X to become assigned, and could be a labeling/2 goal. The algorithm calls Goal repeatedly with a progressively tighter upper (lower) bound on X until a proof of optimality is obtained, at which time Goal and X are unified with values corresponding to the optimal solution.

The Options argument of labeling/2 controls the order in which variables are selected for assignment (variable choice heuristic), the way in which choices are made for the selected variable (value choice heuristic), and whether all solutions or a single, optimal solution should be found. The options are divided into four groups. One option may be selected per group. Finally, the number of assumptions (choices) made during the search can be collected.

The following options control the order in which the next variable is selected for assignment.
leftmost
The leftmost variable is selected. This is the default.
min
The leftmost variable with the smallest lower bound is selected.
max
The leftmost variable with the greatest upper bound is selected.
ff
The first-fail principle is used: the leftmost variable with the smallest domain is selected.
ffc
The most constrained heuristic is used: a variable with the smallest domain is selected, breaking ties by (a) selecting the variable that has the most constraints suspended on it and (b) selecting the leftmost one.
variable(Sel)
Sel is a predicate to select the next variable. Given Vars, the variables that remain to label, it will be called as Sel(Vars,Selected,Rest).

Sel is expected to succeed deterministically, unifying Selected and Rest with the selected variable and the remaining list, respectively.

Sel should be a callable term, optionally with a module prefix, and the arguments Vars,Selected,Rest will be appended to it. For example, if Sel is mod:sel(Param), it will be called as mod:sel(Param,Vars,Selected,Rest).

The following options control the way in which choices are made for the selected variable X:

step
Makes a binary choice between X #= B and X #\= B, where B is the lower or upper bound of X. This is the default.
enum
Makes a multiple choice for X corresponding to the values in its domain.
bisect
Makes a binary choice between X #=< M and X #> M, where M is the midpoint of the domain of X. This strategy is also known as domain splitting.
value(Enum)
Enum is a predicate which should narrow the domain of X, possibly but not necessarily to a singleton. It will be called as Enum(X,Rest,BB) where Rest is the list of variables that need labeling except X, and BB is a parameter described below.

Enum is expected to succeed non-deterministically, narrowing the domain of X, and to backtrack one or more times, providing alternative narrowings. In all solutions except the first one, it must call the auxiliary predicate apply_bound(BB) to ensure that branch-and-bound search works correctly.

Enum should be a callable term, optionally with a module prefix, and the arguments X,Rest,BB will be appended to it. For example, if Enum is mod:enum(Param), it will be called as mod:enum(Param,X,Rest,BB).

The following options control the order in which the choices are made for the selected variable X. Not useful with the value(Enum) option:

up
The domain is explored in ascending order. This is the default.
down
The domain is explored in descending order.

The following options control whether all solutions should be enumerated by backtracking or whether a single solution that minimizes (maximizes) X is returned, if one exists.

all
All solutions are enumerated. This is the default.
minimize(X)
maximize(X)
Uses a branch-and-bound algorithm to find an assignment that minimizes (maximizes) the domain variable X. The labeling should constrain X to become assigned for all assignments of Variables.

Finally, the following option counts the number of assumptions (choices) made during the search:

assumptions(K)
When a solution is found, K is unified with the number of choices made.

For example, to enumerate solutions using a static variable ordering, use:

| ?- constraints(Variables),
     labeling([], Variables).
     %same as [leftmost,step,up,all]

To minimize a cost function using branch-and-bound search, a dynamic variable ordering using the first-fail principle, and domain splitting exploring the upper part of domains first, use:

| ?- constraints(Variables, Cost),
     labeling([ff,bisect,down,minimize(Cost)], Variables).

The file library('clpfd/examples/tsp.pl') contains an example of user-defined variable and value choice heuristics.

As opposed to the predicates above which search for consistent assignments to domain variables, the following predicate searches for a consistent ordering among tasks competing for an exclusive resource, without necessarily fixing their start times:

order_resource(+Options, +Resource)

where Options is a list of search options and Resource represents a resource as returned by serialized/3 (see Combinatorial Constraints) on which tasks must be serialized. True if a total ordering can be imposed on the tasks, enumerating all such orderings via backtracking.

The search options control the construction of the total ordering. It may contain at most one of the following atoms, selecting a strategy:

first
The ordering is built by repetitively selecting some task to be placed before all others.
last
The ordering is built by repetitively selecting some task to be placed after all others.

and at most one of the following atoms, controlling which task to select at each step. If first is chosen (the default), the task with the smallest value is selected, otherwise the task with the greatest value is selected.

est
The tasks are ordered by earliest start time.
lst
The tasks are ordered by latest start time.
ect
The tasks are ordered by earliest completion time.
lct
The tasks are ordered by latest completion time.

[first,est] (the default) and [last,lct] can be good heuristics.


Node:Statistics Predicates, Next:, Previous:Enumeration Predicates, Up:CLPFD

Statistics Predicates

The following predicates can be used to get execution statistics.

fd_statistics(?Key, ?Value)

This allows a program to access execution statistics specific to this solver. General statistics about CPU time and memory consumption etc. is available from the built-in predicate statistics/2.

For each of the possible keys Key, Value is unified with the current value of a counter which is simultaneously zeroed. The following counters are maintained. See The Constraint System, for details of what they all mean:

resumptions
The number of times a constraint was resumed.
entailments
The number of times a (dis)entailment was detected by a constraint.
prunings
The number of times a domain was pruned.
backtracks
The number of times a contradiction was found by a domain being wiped out, or by a global constraint signalling failure. Other causes of backtracking, such as failed Prolog tests, are not covered by this counter.
constraints
The number of constraints created.

fd_statistics

Displays on the standard error stream a summary of the above statistics. All counters are zeroed.


Node:Answer Constraints, Next:, Previous:Statistics Predicates, Up:CLPFD

Answer Constraints

By default, the answer constraint only shows the projection of the store onto the variables that occur in the query, but not any constraints that may be attached to these variables, nor any domains or constraints attached to other variables. This is a conscious decision, as no efficient algorithm for projecting answer constraints onto the query variables is known for this constraint system.

It is possible, however, to get a complete answer constraint including all variables that took part in the computation and their domains and attached constraints. This is done by asserting a clause for the following predicate:

clpfd:full_answer [Hook]

If false (the default), the answer constraint only contains the domains of the query variables. If true, the answer constraints contains the domains and any attached constraints of all variables. Initially defined as a dynamic predicate with no clauses.


Node:The Constraint System, Next:, Previous:Answer Constraints, Up:CLPFD

The Constraint System


Node:Definitions, Next:, Previous:The Constraint System, Up:The Constraint System

Definitions

The constraint system is based on domain constraints and indexicals. A domain constraint is an expression X::I, where X is a domain variable and I is a nonempty set of integers.

A set S of domain constraints is called a store. D(X,S), the domain of X in S, is defined as the intersection of all I such that X::I belongs to S. The store is contradictory if the domain of some variable is empty; otherwise, it is consistent. A consistent store S' is an extension of a store S iff, for all variables X, D(X,S') is contained in D(X,S).

The following definitions, adapted from [Van Hentenryck et al. 95], define important notions of consistency and entailment of constraints wrt. stores.

A ground constraint is true if it holds and false otherwise.

A constraint C is domain-consistent wrt. S iff, for each variable Xi and value Vi in D(Xi,S), there exist values Vj in D(Xj,S), 1 =< j =< n, i\=j, such that C(V1,...,Vn) is true.

A constraint C is domain-entailed by S iff, for all values Vj in D(Xj,S), 1 =< j =< n, C(V1,...,Vn) is true.

Let D'(X,S) denote the interval min(D(X,S))..max(D(X,S)).

A constraint C is interval-consistent wrt. S iff, for each variable Xi there exist values Vj in D'(Xj,S), 1 =< j =< n, i\=j, such that C(V1,...,min(D(Xi,S)),...,Vn) and C(V1,...,max(D(Xi,S)),...,Vn) are both true.

A constraint C is interval-entailed by S iff, for all values Vj in D'(Xj,S), 1 =< j =< n, C(V1,...,Vn) is true.

Finally, a constraint is domain-disentailed (interval-disentailed) by S iff its negation is domain-entailed (interval-entailed) by S.


Node:Pitfalls of Interval Reasoning, Previous:Definitions, Up:The Constraint System

Pitfalls of Interval Reasoning

In most circumstances, arithmetic constraints only maintain interval-consistency and only detect interval-entailment and -disentailment. Note that there are cases where an interval-consistency maintaining constraint may detect a contradiction when the constraint is not yet interval-disentailed, as the following example illustrates. Note that X #\= Y maintains domain consistency if both arguments are constants or variables:

| ?- X+Y #= Z, X=1, Z=6, Y in 1..10, Y #\= 5.

no
| ?- X+Y #= Z #<=> B, X=1, Z=6, Y in 1..10, Y #\= 5.

X = 1,
Z = 6,
Y in(1..4)\/(6..10),
B in 0..1

Since 1+5#=6 holds, X+Y #= Z is not interval-disentailed, although any attempt to make it interval-consistent wrt. the store results in a contradictory store.


Node:Defining Global Constraints, Next:, Previous:The Constraint System, Up:CLPFD

Defining Global Constraints


Node:The Global Constraint Programming Interface, Next:, Previous:Defining Global Constraints, Up:Defining Global Constraints

The Global Constraint Programming Interface

This section describes a programming interface by means of which new constraints can be written. The interface consists of a set of predicates provided by this library module. Constraints defined in this way can take arbitrary arguments and may use any constraint solving algorithm, provided it makes sense. Reification cannot be expressed in this interface; instead, reification may be achieved by explicitly passing a 0/1-variable to the constraint in question.

Global constraints have state which may be updated each time the constraint is resumed. The state information may be used e.g. in incremental constraint solving.

The following two predicates are the principal entrypoints for defining and posting new global constraints:

clpfd:dispatch_global(+Constraint, +State0, -State, -Actions) [Hook]

Tells the solver how to solve constraints of the form Constraint. Defined as a dynamic, multifile predicate.

When defining a new constraint, a clause of this predicate must be added. Its body defines a constraint solving method and should always succeed deterministically. When a global constraint is called or resumed, the solver will call this predicate to deal with the constraint.

State0 and State are the old and new state respectively.

The constraint solving method must not invoke the constraint solver recursively e.g. by binding variables or posting new constraints; instead, Actions should be unified with a list of requests to the solver. Each request should be of the following form:

exit
The constraint has become entailed, and ceases to exist.
fail
The constraint has become disentailed, causing the solver to backtrack.
X = V
The solver binds X to V.
X in R
The solver constrains X to be a member of the ConstantRange R (see Syntax of Indexicals).
X in_set S
The solver constrains X to be a member of the FD set S (see FD Set Operations).
call(Goal)
The solver calls the goal or constraint Goal, which should be module prefixed unless it is a built-in predicate or an exported predicate of the clpfd module.

The constraint solving method is assumed to be idempotent. That is, if the Actions were performed by the solver and the constraint resumed, it should not produce any further Actions. Thus the solver will not check for the resumption conditions for the given constraint, while performing its Actions.

fd_global(+Constraint, +State, +Susp)

where Constraint is a constraint goal, State is its initial state, and Susp is a term encoding how the constraint should wake up in response to domain changes. This posts the constraint.

Susp is a list of F(Var) terms where Var is a variable to suspend on and F is a functor encoding when to wake up:

dom(X)
wake up when the domain of X has changed
min(X)
wake up when the lower bound of X has changed
max(X)
wake up when the upper bound of X has changed
minmax(X)
wake up when the lower or upper of X has changed
val(X)
wake up when X has become ground

For an example of usage, see A Global Constraint Example.


Node:Reflection Predicates, Next:, Previous:The Global Constraint Programming Interface, Up:Defining Global Constraints

Reflection Predicates

The constraint solving method needs access to information about the current domains of variables. This is provided by the following predicates, which are all constant time operations.

fd_min(?X, ?Min)

where X is a domain variable (or an integer). Min is unified with the smallest value in the current domain of X, i.e. an integer or the atom inf denoting minus infinity.

fd_max(?X, ?Max)

where X is a domain variable (or an integer). Max is unified with the upper bound of the current domain of X, i.e. an integer or the atom sup denoting infinity.

fd_size(?X, ?Size)

where X is a domain variable (or an integer). Size is unified with the size of the current domain of X, if the domain is bounded, or the atom sup otherwise.

fd_set(?X, ?Set)

where X is a domain variable (or an integer). Set is unified with an FD set term denoting the internal representation of the current domain of X; see below.

fd_dom(?X, ?Range)

where X is a domain variable (or an integer). Range is unified with a ConstantRange (see Syntax of Indexicals) denoting the the current domain of X.

fd_degree(?X, ?Degree)

where X is a domain variable (or an integer). Degree is unified with the number of constraints that are attached to X. NOTE: this number may include some constraints that have been detected as entailed.

The following predicate can be used for computing the set of variables that are transitively connected via constraints to some given variables.

fd_closure(+Vars, -Closure)

Given a list Vars of domain variables, Closure is the set of variables (including Vars) that can be transitively reached via constraints posted so far.


Node:FD Set Operations, Next:, Previous:Reflection Predicates, Up:Defining Global Constraints

FD Set Operations

The domains of variables are internally represented compactly as FD set terms. The details of this representation are subject to change and should not be relied on. Therefore, a number of operations on FD sets are provided, as such terms play an important role in the interface. The following operations are the primitive ones:

is_fdset(+Set)

Set is a valid FD set.

empty_fdset(?Set)

Set is the empty FD set.

fdset_parts(?Set, ?Min, ?Max, ?Rest)

Set is an FD set which is a union of the non-empty interval Min..Max and the FD set Rest, and all elements of Rest are greater than Max+1. Min and Max are both integers or the atoms inf and sup, denoting minus and plus infinity, respectively. Either Set or all the other arguments must be ground.

The following operations can all be defined in terms of the primitive ones, but in most cases, a more efficient implementation is used:

empty_interval(+Min, +Max)

Min..Max is an empty interval.

fdset_interval(?Set, ?Min, ?Max)

Set is an fdset which is the non-empty interval Min..Max.

fdset_singleton(?Set, ?Elt)

Set is an FD set containing Elt only. At least one of the arguments must be ground.

fdset_min(+Set, -Min)

Min is the lower bound of Set.

fdset_max(+Set, -Min)

Max is the upper bound of Set. This operation is linear in the number of intervals of Set.

fdset_size(+Set, -Size)

Size is the cardinality of Set, represented as sup if Set is infinite. This operation is linear in the number of intervals of Set.

list_to_fdset(+List, -Set)

Set is the FD set containing the elements of List. Slightly more efficient if List is ordered.

fdset_to_list(+Set, -List)

List is an ordered list of the elements of Set, which must be finite.

range_to_fdset(+Range, -Set)

Set is the FD set containing the elements of the ConstantRange (see Syntax of Indexicals) Range.

fdset_to_range(+Set, -Range)

Range is a constant interval, a singleton constant set, or a union of such, denoting the same set as Set.

fdset_add_element(+Set1, +Elt -Set2)

Set2 is Set1 with Elt inserted in it.

fdset_del_element(+Set1, +Elt, -Set2)

Set2 is like Set1 but with Elt removed.

fdset_disjoint(+Set1, +Set2)

The two FD sets have no elements in common.

fdset_intersect(+Set1, +Set2)

The two FD sets have at least one element in common.

fdset_intersection(+Set1, +Set2, -Intersection)

Intersection is the intersection between Set1 and Set2.

fdset_intersection(+Sets, -Intersection)

Intersection is the intersection of all the sets in Sets.

fdset_member(?Elt, +Set)

is true when Elt is a member of Set. If Elt is unbound, Set must be finite.

fdset_eq(+Set1, +Set2)

Is true when the two arguments represent the same set i.e. they are identical.

fdset_subset(+Set1, +Set2)

Every element of Set1 appears in Set2.

fdset_subtract(+Set1, +Set2, -Difference)

Difference contains all and only the elements of Set1 which are not also in Set2.

fdset_union(+Set1, +Set2, -Union)

Union is the union of Set1 and Set2.

fdset_union(+Sets, -Union)

Union is the union of all the sets in Sets.

fdset_complement(+Set, -Complement)

Complement is the complement of Set wrt. inf..sup.


Node:A Global Constraint Example, Previous:FD Set Operations, Up:Defining Global Constraints

A Global Constraint Example

The following example defines a new global constraint exactly(X,L,N) which is true if X occurs exactly N times in the list L of integers and domain variables. N must be an integer when the constraint is posted. A version without this restriction and defined in terms of reified equalities was presented earlier; see Reified Constraints.

This example illustrates the use of state information. The state has two components: the list of variables that could still be X, and the number of variables still required to be X.

The constraint is defined to wake up on any domain change.

/*
An implementation of exactly(I, X[1]...X[m], N):

Necessary condition: 0 =< N =< m.
Rewrite rules:

[1] |= X[i]=I  ==> exactly(I, X[1]...X[i-1],X[i+1]...X[m], N-1):
[2] |= X[i]\=I ==> exactly(I, X[1]...X[i-1],X[i+1]...X[m], N):
[3] |= N=0     ==> X[1]\=I ... X[m]\=I
[4] |= N=m     ==> X[1]=I  ... X[m]=I
*/
:- use_module(library(clpfd)).

% the entrypoint
exactly(I, Xs, N) :-
        dom_suspensions(Xs, Susp),
        fd_global(exactly(I,Xs,N), state(Xs,N), Susp).

dom_suspensions([], []).
dom_suspensions([X|Xs], [dom(X)|Susp]) :-
        dom_suspensions(Xs, Susp).

% the solver method
:- multifile clpfd:dispatch_global/4.
clpfd:dispatch_global(exactly(I,_,_), state(Xs0,N0), state(Xs,N), Actions) :-
        exactly_solver(I, Xs0, Xs, N0, N, Actions).

exactly_solver(I, Xs0, Xs, N0, N, Actions) :-
        ex_filter(Xs0, Xs, N0, N, I),
        length(Xs, M),
        (   N=:=0 -> Actions = [exit|Ps], ex_neq(Xs, I, Ps)
        ;   N=:=M -> Actions = [exit|Ps], ex_eq(Xs, I, Ps)
        ;   N>0, N<M -> Actions = []
        ;   Actions = [fail]
        ).

% rules [1,2]: filter the X's, decrementing N
ex_filter([], [], N, N, _).
ex_filter([X|Xs], Ys, L, N, I) :- X==I, !,
        M is L-1,
        ex_filter(Xs, Ys, M, N, I).
ex_filter([X|Xs], Ys0, L, N, I) :-
        fd_set(X, Set),
        fdset_member(I, Set), !,
        Ys0 = [X|Ys],
        ex_filter(Xs, Ys, L, N, I).
ex_filter([_|Xs], Ys, L, N, I) :-
        ex_filter(Xs, Ys, L, N, I).

% rule [3]: all must be neq I
ex_neq(Xs, I, Ps) :-
        fdset_singleton(Set0, I),
        fdset_complement(Set0, Set),
        eq_all(Xs, Set, Ps).

% rule [4]: all must be eq I
ex_eq(Xs, I, Ps) :-
        fdset_singleton(Set, I),
        eq_all(Xs, Set, Ps).

eq_all([], _, []).
eq_all([X|Xs], Set, [X in_set Set|Ps]) :-
        eq_all(Xs, Set, Ps).

end_of_file.

% sample queries:
| ?- exactly(5,[A,B,C],1), A=5.

A = 5,
B in(inf..4)\/(6..sup),
C in(inf..4)\/(6..sup)

| ?- exactly(5,[A,B,C],1), A in 1..2, B in 3..4.

C = 5,
A in 1..2,
B in 3..4


Node:Defining Primitive Constraints, Next:, Previous:Defining Global Constraints, Up:CLPFD

Defining Primitive Constraints

Indexicals are the principal means of defining constraints, but it is usually not necessary to resort to this level of programming--most commonly used constraints are available in a library and/or via macro-expansion. The key feature about indexicals is that they give the programmer precise control over aspects of the operational semantics of the constraints. Trade-offs can be made between the computational cost of the constraints and their pruning power. The indexical language provides many degrees of freedom for the user to select the level of consistency to be maintained depending on application-specific needs.


Node:Indexicals, Next:, Previous:Defining Primitive Constraints, Up:Defining Primitive Constraints

Indexicals

An indexical is a reactive functional rule of the form X in R, where R is a set valued range expression (see below). See Syntax of Indexicals, for a grammar defining indexicals and range expressions.

Indexicals can play one of two roles: propagating indexicals are used for constraint solving, and checking indexicals are used for entailment checking. When a propagating indexical fires, R is evaluated in the current store S, which is extended by adding the new domain constraint X::S(R) to the store, where S(R) denotes the value of R in S. When a checking indexical fires, it checks if D(X,S) is contained in S(R), and if so, the constraint corresponding to the indexical is detected as entailed.


Node:Range Expressions, Next:, Previous:Indexicals, Up:Defining Primitive Constraints

Range Expressions

A range expression has one of the following forms, where Ri denote range expressions, Ti denote integer valued term expressions, S(Ti) denotes the integer value of Ti in S, X denotes a variable, I denotes an integer, and S denotes the current store.

dom(X)
evaluates to D(X,S)
{T1,...,Tn}
evaluates to {S(T1),...,S(Tn)}. Any term expression containing a subexpression which is a variable that is not "quantified" by unionof/3 will only be evaluated when this variable has been assigned.
T1..T2
evaluates to the interval between S(T1) and S(T2).
R1/\R2
evaluates to the intersection of S(R1) and S(R2)
R1\/R2
evaluates to the union of S(R1) and S(R2)
\R2
evaluates to the complement of S(R2)
R1+R2
R1+T2
evaluates to S(R2) or S(T2) added pointwise to S(R1)
-R2
evaluates to S(R2) negated pointwise
R1-R2
R1-T2
T1-R2
evaluates to S(R2) or S(T2) subtracted pointwise from S(R1) or S(T1)
R1 mod R2
R1 mod T2
evaluates to S(R1) pointwise modulo S(R2) or S(T2)
R1 ? R2
evaluates to S(R2) if S(R1) is a non-empty set; otherwise, evaluates to the empty set. This expression is commonly used in the context (R1 ? (inf..sup) \/ R3), which evaluates to S(R3) if S(R1) is an empty set; otherwise, evaluates to inf..sup. As an optimization, R3 is not evaluated while the value of R1 is a non-empty set.
unionof(X,R1,R2)
evaluates to the union of S(Expr_1)...S(Expr_N), where each Expr_I has been formed by substituting K for X in R2, where K is the I:th element of S(R1). See N Queens, for an example of usage. N.B. If S(R1) is infinite, the evaluation of the indexical will be abandoned, and the indexical will simply suspend.
switch(T1,MapList)
evaluates to S(Expr) if S(T1) equals Key and MapList contains a pair Key-Expr. Otherwise, evaluates to the empty set.

When used in the body of an FD predicate (see Goal Expanded Constraints), a relation/3 expression expands to two indexicals, each consisting of a switch/2 expression nested inside a unionof/3 expression. Thus, the following constraints are equivalent:

p(X, Y) +: relation(X, [1-{1},2-{1,2},3-{1,2,3}], Y).

q(X, Y) +:
        X in unionof(B,dom(Y),switch(B,[1-{1,2,3},2-{2,3},3-{3}])),
        Y in unionof(B,dom(X),switch(B,[1-{1},2-{1,2},3-{1,2,3}])).


Node:Term Expressions, Next:, Previous:Range Expressions, Up:Defining Primitive Constraints

Term Expressions

A term expression has one of the following forms, where T1 and T2 denote term expressions, X denotes a variable, I denotes an integer, and S denotes the current store.

min(X)
evaluates to the minimum of D(X,S)
max(X)
evaluates to the maximum of D(X,S)
card(X)
evaluates to the size of D(X,S)
X
evaluates to the integer value of X. A subexpression of this form, not "quantified" by unionof/3, will cause the evaluation to suspend until the variable is assigned.
I
an integer
inf
minus infinity
sup
plus infinity
-T1
evaluates to S(T1) negated
T1+T2
evaluates to the sum of S(T1) and S(T2)
T1-T2
evaluates to the difference of S(T1) and S(T2)
T1*T2
evaluates to the product of S(T1) and S(T2), where S(T2) must not be negative
T1/>T2
evaluates to the quotient of S(T1) and S(T2), rounded up, where S(T2) must be positive
T1/<T2
evaluates to the quotient of S(T1) and S(T2), rounded down, where S(T2) must be positive
T1 mod T2
evaluates to the modulo of S(T1) and S(T2)


Node:Monotonicity of Indexicals, Next:, Previous:Term Expressions, Up:Defining Primitive Constraints

Monotonicity of Indexicals

A range R is monotone in S iff the value of R in S' is contained in the value of R in S, for every extension S' of S. A range R is anti-monotone in S iff the value of R in S is contained in the value of R in S', for every extension S' of S. By abuse of notation, we will say that X in R is (anti-)monotone iff R is (anti-)monotone.

The consistency or entailment of a constraint C expressed as indexicals X in R in a store S is checked by considering the relationship between D(X,S) and S(R), together with the (anti-)monotonicity of R in S. The details are given in Execution of Propagating Indexicals and Execution of Checking Indexicals.

The solver checks (anti-)monotonicity by requiring that certain variables occurring in the indexical be ground. This sufficient condition can sometimes be false for an (anti-)monotone indexical, but such situations are rare in practice.


Node:FD predicates, Next:, Previous:Monotonicity of Indexicals, Up:Defining Primitive Constraints

FD predicates

The following example defines the constraint X+Y=T as an FD predicate in terms of three indexicals. Each indexical is a rule responsible for removing values detected as incompatible from one particular constraint argument. Indexicals are not Prolog goals; thus, the example does not express a conjunction. However, an indexical may make the store contradictory, in which case backtracking is triggered:

plus(X,Y,T) +:
        X in min(T) - max(Y) .. max(T) - min(Y),
        Y in min(T) - max(X) .. max(T) - min(X),
        T in min(X) + min(Y) .. max(X) + max(Y).

The above definition contains a single clause used for constraint solving. The first indexical wakes up whenever the bounds of S(T) or S(Y) are updated, and removes from D(X,S) any values that are not compatible with the new bounds of T and Y. Note that in the event of "holes" in the domains of T or Y, D(X,S) may contain some values that are incompatible with X+Y=T but go undetected. Like most built-in arithmetic constraints, the above definition maintains interval-consistency, which is significantly cheaper to maintain than domain-consistency and suffices in most cases. The constraint could for example be used as follows:

| ?- X in 1..5, Y in 2..8, plus(X,Y,T).

X in 1..5,
Y in 2..8,
T in 3..13 ?

yes

Thus, when an FD predicate is called, the +: clause is activated.

The definition of a user constraint has to specify what domain constraints should be added to the constraint store when the constraint is posted. Therefore the FD predicate contains a set of indexicals, each representing a domain constraint to be added to the constraint store. The actual domain constraint depends on the constraint store itself. For example, the third indexical in the above FD predicate prescribes the domain constraint T :: 3..13 if the store contains X :: 1..5, Y :: 2..8. As the domain of some variables gets narrower, the indexical may enforce a new, stricter constraint on some other variables. Therefore such an indexical (called a propagating indexical) can be viewed as an agent reacting to the changes in the store by enforcing further changes in the store.

In general there are three stages in the lifetime of a propagating indexical. When it is posted it may not be evaluated immediately (e.g. has to wait until some variables are ground before being able to modify the store). Until the preconditions for the evaluation are satisfied, the agent does not enforce any constraints. When the indexical becomes evaluable the resulting domain constraint is added to the store. The agent then waits and reacts to changes in the domains of variables occurring in the indexical by re-evaluating it and adding the new, stricter constraint to the store. Eventually the computation reaches a phase when no further refinement of the store can result in a more precise constraint (the indexical is entailed by the store), and then the agent can cease to exist.

A necessary condition for the FD predicate to be correctly defined is the following: for any store mapping each variable to a singleton domain the execution of the indexicals should succeed without contradiction exactly when the predicate is intended to be true.

There can be several alternative definitions for the same user constraint with different strengths in propagation. For example, the definition of plusd below encodes the same X+Y=T constraint as the plus predicate above, but maintaining domain consistency:

plusd(X,Y,T) +:
        X in dom(T) - dom(Y),
        Y in dom(T) - dom(X),
        T in dom(X) + dom(Y).

| ?- X in {1}\/{3}, Y in {10}\/{20}, plusd(X, Y, T).

X in{1}\/{3},
Y in{10}\/{20},
T in{11}\/{13}\/{21}\/{23} ?

yes

This costs more in terms of execution time, but gives more precise results. For singleton domains plus and plusd behave in the same way.

In our design, general indexicals can only appear in the context of FD predicate definitions. The rationale for this restriction is the need for general indexicals to be able to suspend and resume, and this ability is only provided by the FD predicate mechanism.

If the program merely posts a constraint, it suffices for the definition to contain a single clause for solving the constraint. If a constraint is reified or occurs in a propositional formula, the definition must contain four clauses for solving and checking entailment of the constraint and its negation. The role of each clause is reflected in the "neck" operator. The following table summarizes the different forms of indexical clauses corresponding to a constraint C. In all cases, Head should be a compound term with all arguments being distinct variables:

Head +: Indexicals.
The clause consists of propagating indexicals for solving C.
Head -: Indexicals.
The clause consists of propagating indexicals for solving the negation of C.
Head +? Indexical.
The clause consists of a single checking indexical for testing entailment of C.
Head -? Indexical.
The clause consists of a single checking indexical for testing entailment of the negation of C.

When a constraint is reified, the solver spawns two reactive agents corresponding to detecting entailment and disentailment. Eventually, one of them will succeed in this and consequently will bind B to 0 or 1. A third agent is spawned, waiting for B to become assigned, at which time the constraint (or its negation) is posted. In the mean time, the constraint may have been detected as (dis)entailed, in which case the third agent is dismissed. The waiting is implemented by means of the coroutining facilities of SICStus Prolog.

As an example of a constraint with all methods defined, consider the following library constraint defining a disequation between two domain variables:

'x\\=y'(X,Y) +:
        X in \{Y},
        Y in \{X}.
'x\\=y'(X,Y) -:
        X in dom(Y),
        Y in dom(X).
'x\\=y'(X,Y) +?
        X in \dom(Y).
'x\\=y'(X,Y) -?
        X in {Y}.

The following sections provide more precise coding rules and operational details for indexicals. X in R denotes an indexical corresponding to a constraint C. S denotes the current store.


Node:Execution of Propagating Indexicals, Next:, Previous:FD predicates, Up:Defining Primitive Constraints

Execution of Propagating Indexicals

Consider the definition of a constraint C containing a propagating indexical X in R. Let TV(X,C,S) denote the set of values for X that can make C true in some ground extension of the store S. Then the indexical should obey the following coding rules:

If the coding rules are observed, S(R) can be proven to contain TV(X,C,S) for all stores in which R is monotone. Hence it is natural for the implementation to wait until R becomes monotone before admitting the propagating indexical for execution. The execution of X in R thus involves the following:

A propagating indexical is scheduled for execution as follows:


Node:Execution of Checking Indexicals, Next:, Previous:Execution of Propagating Indexicals, Up:Defining Primitive Constraints

Execution of Checking Indexicals

Consider the definition of a constraint C containing a checking indexical X in R. Let FV(X,C,S) denote the set of values for X that can make C false in some ground extension of the store S. Then the indexical should obey the following coding rules:

If the coding rules are observed, S(R) can be proven to exclude FV(X,C,S) for all stores in which R is anti-monotone. Hence it is natural for the implementation to wait until R becomes anti-monotone before admitting the checking indexical for execution. The execution of X in R thus involves the following:

A checking indexical is scheduled for execution as follows:


Node:Goal Expanded Constraints, Previous:Execution of Checking Indexicals, Up:Defining Primitive Constraints

Goal Expanded Constraints

The arithmetic, membership, and propositional constraints described earlier are transformed at compile time to conjunctions of goals of library constraints.

Sometimes it is necessary to postpone the expansion of a constraint until runtime, e.g. if the arguments are not instantiated enough. This can be achieved by wrapping call/1 around the constraint.

Although space economic (linear in the size of the source code), the expansion of a constraint to library goals can have an overhead compared to expressing the constraint in terms of indexicals. Temporary variables holding intermediate values may have to be introduced, and the grain size of the constraint solver invocations can be rather small. The translation of constraints to library goals has been greatly improved in the current version, so these problems have virtually disappeared. However, for backward compatibility, an implementation by compilation to indexicals of the same constraints is also provided. An FD predicate may be defined by a single clause:

    Head +: Constraint.

where Constraint is an arithmetic constraint or an element/3 or a relation/3 constraint. This translation is only available for +: clauses; thus, Head cannot be reified.

In the case of arithmetic constraints, the constraint must be over linear terms (see Syntax of Indexicals). The memory consumption of the FD predicate will be quadratic in the size of the source code. The alternative version of sum/8 in Send More Money illustrates this technique.

In the case of element(X,L,Y) or relation(X,L,Y), the memory consumption of the FD predicate will be linear in the size of the source code. The execution time of the initial evaluation of the FD predicate will be linear in the size of the initial domains for X and Y; if these domains are infinite, no propagation will take place.


Node:Example Programs, Next:, Previous:Defining Primitive Constraints, Up:CLPFD

Example Programs

This section contains a few example programs. The first two programs are included in a benchmark suite that comes with the distribution. The benchmark suite is run by typing:

| ?- compile(library('clpfd/examples/bench')).
| ?- bench.


Node:Send More Money, Next:, Previous:Example Programs, Up:Example Programs

Send More Money

Let us return briefly to the Send More Money problem (see A Constraint Satisfaction Problem). Its sum/8 predicate will expand to a space-efficient conjunction of library constraints. A faster but more memory consuming version is defined simply by changing the neck symbol of sum/8 from :- to +:, thus turning it into an FD predicate:

sum(S, E, N, D, M, O, R, Y) +:
                  1000*S + 100*E + 10*N + D
     +            1000*M + 100*O + 10*R + E
     #= 10000*M + 1000*O + 100*N + 10*E + Y.


Node:N Queens, Next:, Previous:Send More Money, Up:Example Programs

N Queens

The problem is to place N queens on an NxN chess board so that no queen is threatened by another queen.

The variables of this problem are the N queens. Each queen has a designated row. The problem is to select a column for it.

The main constraint of this problem is that no queen threaten another. This is encoded by the no_threat/3 constraint and holds between all pairs (X,Y) of queens. It could be defined as

no_threat(X, Y, I) :-
        X   #\= Y,
        X+I #\= Y,
        X-I #\= Y.

However, this formulation introduces new temporary domain variables and creates twelve fine-grained indexicals. Worse, the arithmetic constraints are only guaranteed to maintain interval-consistency and so may miss some opportunities for pruning elements in the middle of domains.

A better idea is to formulate no_threat/3 as an FD predicate with two indexicals, as shown in the program below. This constraint will not fire until one of the queens has been assigned (the corresponding indexical does not become monotone until then). Hence, the constraint is still not as strong as it could be.

For example, if the domain of one queen is (2..3), then it will threaten any queen placed in column 2 or 3 on an adjacent row, no matter which of the two open positions is chosen for the first queen. The commented out formulation of the constraint captures this reasoning, and illustrates the use of the unionof/3 operator. This stronger version of the constraint indeed gives less backtracking, but is computationally more expensive and does not pay off in terms of execution time, except possibly for very large chess boards.

It is clear that no_threat/3 cannot detect any incompatible values for a queen with domain of size greater than three. This observation is exploited in the third version of the constraint.

The first-fail principle is appropriate in the enumeration part of this problem.

:- use_module(library(clpfd)).

queens(N, L, LabelingType) :-
     length(L, N),
     domain(L, 1, N),
     constrain_all(L),
     labeling(LabelingType, L).

constrain_all([]).
constrain_all([X|Xs]) :-
     constrain_between(X, Xs, 1),
     constrain_all(Xs).

constrain_between(_X, [], _N).
constrain_between(X, [Y|Ys], N) :-
     no_threat(X, Y, N),
     N1 is N+1,
     constrain_between(X, Ys, N1).


% version 1: weak but efficient
no_threat(X, Y, I) +:
     X in \({Y} \/ {Y+I} \/ {Y-I}),
     Y in \({X} \/ {X+I} \/ {X-I}).

/*
% version 2: strong but very inefficient version
no_threat(X, Y, I) +:
    X in unionof(B,dom(Y),\({B} \/ {B+I} \/ {B-I})),
    Y in unionof(B,dom(X),\({B} \/ {B+I} \/ {B-I})).

% version 3: strong but somewhat inefficient version
no_threat(X, Y, I) +:
    X in (4..card(Y)) ? (inf..sup) \/
          unionof(B,dom(Y),\({B} \/ {B+I} \/ {B-I})),
    Y in (4..card(X)) ? (inf..sup) \/
          unionof(B,dom(X),\({B} \/ {B+I} \/ {B-I})).
*/

| ?- queens(8, L, [ff]).

L = [1,5,8,6,3,7,2,4] ?


Node:Cumulative Scheduling, Previous:N Queens, Up:Example Programs

Cumulative Scheduling

This example is a very small scheduling problem. We consider seven tasks where each task has a fixed duration and a fixed amount of used resource:

TASK    DURATION        RESOURCE
====    ========        ========
t1            16               2
t2             6               9
t3            13               3
t4             7               7
t5             5              10
t6            18               1
t7             4              11

The goal is to find a schedule that minimizes the completion time for the schedule while not exceeding the capacity 13 of the resource. The resource constraint is succinctly captured by a cumulative/4 constraint. Branch-and-bound search is used to find the minimal completion time.

This example was adapted from [Beldiceanu & Contejean 94].

:- use_module(library(clpfd)).
:- use_module(library(lists), [append/3]).

schedule(Ss, End) :-
        length(Ss, 7),
        Ds = [16, 6,13, 7, 5,18, 4],
        Rs = [ 2, 9, 3, 7,10, 1,11],
        domain(Ss, 1, 30),
        domain([End], 1, 50),
        after(Ss, Ds, End),
        cumulative(Ss, Ds, Rs, 13),
        append(Ss, [End], Vars),
        labeling([minimize(End)], Vars). % label End last

after([], [], _).
after([S|Ss], [D|Ds], E) :- E #>= S+D, after(Ss, Ds, E).

%% End of file

| ?- schedule(Ss, End).

Ss = [1,17,10,10,5,5,1],
End = 23 ?


Node:Syntax Summary, Previous:Example Programs, Up:CLPFD

Syntax Summary


Node:Syntax of Indexicals, Next:, Previous:Syntax Summary, Up:Syntax Summary

Syntax of Indexicals

X --> variable                { domain variable }

Constant --> integer
  |   inf                         { minus infinity }
  |   sup                         { plus infinity }

Term --> Constant
  |   X                     { suspend until assigned }
  |   min(X)                { min. of domain of X }
  |   max(X)                { max. of domain of X }
  |   card(X)               { size of domain of X }
  |   - Term
  |   Term + Term
  |   Term - Term
  |   Term * Term
  |   Term /> Term               { division rounded up }
  |   Term /< Term               { division rounded down }
  |   Term mod Term

TermSet --> {Term,...,Term}

Range --> TermSet
  |   dom(X)                          { domain of X }
  |   Term..Term                      { interval }
  |   Range/\Range                     { intersection }
  |   Range\/Range                     { union }
  |   \Range                          { complement }
  |   - Range                         { pointwise negation }
  |   Range + Range                   { pointwise addition }
  |   Range - Range                   { pointwise subtraction }
  |   Range mod Range                 { pointwise modulo }
  |   Range + Term                    { pointwise addition }
  |   Range - Term                    { pointwise subtraction }
  |   Term - Range                    { pointwise subtraction }
  |   Range mod Term                  { pointwise modulo }
  |   Range ? Range
  |   unionof(X,Range,Range)
  |   switch(Term,MapList)

ConstantSet --> {integer,...,integer}

ConstantRange --> ConstantSet
  |   Constant..Constant
  |   ConstantRange/\ConstantRange
  |   ConstantRange\/ConstantRange
  |   \ConstantRange

MapList --> []
  |   [integer-ConstantRange|MapList]

CList --> []
  |   [integer|CList]

Indexical --> X in Range

Indexicals --> Indexical
  |   Indexical, Indexicals

ConstraintBody --> Indexicals
   |  LinExpr RelOp LinExpr
   |  element(X,CList,X)
   |  relation(X,MapList,X)

Head --> term  { a compound term with unique variable args }

TellPos --> Head +: ConstraintBody.
TellNeg --> Head -: ConstraintBody.
AskPos --> Head +? Indexical.
AskNeg --> Head -? Indexical.

ConstraintDef -->
      TellPos. [TellNeg.] [AskPos.] [AskNeg.]


Node:Syntax of Arithmetic Expressions, Next:, Previous:Syntax of Indexicals, Up:Syntax Summary

Syntax of Arithmetic Expressions

X --> variable                { domain variable }

N --> integer

LinExpr --> N                { linear expression }
  |   X
  |   N * X
  |   N * N
  |   LinExpr + LinExpr
  |   LinExpr - LinExpr

Expr --> LinExpr
  |   Expr + Expr
  |   Expr - Expr
  |   Expr * Expr
  |   Expr / Expr                { integer division }
  |   Expr mod Expr
  |   min(Expr,Expr)
  |   max(Expr,Expr)
  |   abs(Expr)

RelOp --> #= | #\= | #< | #=< | #> | #>=


Node:Operator Declarations, Previous:Syntax of Arithmetic Expressions, Up:Syntax Summary

Operator Declarations

:- op(1200, xfx, [+:,-:,+?,-?]).
:- op(760,  yfx, #<=>).
:- op(750,  xfy, #=>).
:- op(750,  yfx, #<=).
:- op(740,  yfx, #\/).
:- op(730,  yfx, #\).
:- op(720,  yfx, #/\).
:- op(710,   fy, #\).
:- op(700,  xfx, [in,in_set]).
:- op(700,  xfx, [#=,#\=,#<,#=<,#>,#>=]).
:- op(550,  xfx, ..).
:- op(500,   fy, \).
:- op(490,  yfx, ?).
:- op(400,  yfx, [/>,/<]).


Node:CHR, Next:, Previous:CLPFD, Up:Top

Constraint Handling Rules


Node:CHR Copyright, Next:, Previous:CHR, Up:CHR

Copyright

This chapter is Copyright © 1996-98 LMU

LMU (Ludwig-Maximilians-University)
Munich, Germany

Permission is granted to make and distribute verbatim copies of this chapter provided the copyright notice and this permission notice are preserved on all copies.

Permission is granted to copy and distribute modified versions of this chapter under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.

Permission is granted to copy and distribute translations of this chapter into another language, under the above conditions for modified versions, except that this permission notice may be stated in a translation approved by LMU.


Node:CHR Introduction, Next:, Previous:CHR Copyright, Up:CHR

Introduction

Experience from real-life applications using constraint-based programming has shown that typically, one is confronted with a heterogeneous mix of different types of constraints. To be able to express constraints as they appear in the application and to write and combine constraint systems, a special purpose language for writing constraint systems called constraint handling rules (CHR) was developed. CHR have been used to encode a wide range of constraint handlers (solvers), including new domains such as terminological and temporal reasoning. Several CHR libraries exist in declarative languages such as Prolog and LISP, worldwide more than 20 projects use CHR. You can find more information about CHR in [Fruehwirth 98] or at URL: http://www.pst.informatik.uni-muenchen.de/personen/fruehwir/chr-intro.html

The high-level CHR are an excellent tool for rapid prototyping and implementation of constraint handlers. The usual abstract formalism to describe a constraint system, i.e. inference rules, rewrite rules, sequents, formulas expressing axioms and theorems, can be written as CHR in a straightforward way. Starting from this executable specification, the rules can be refined and adapted to the specifics of the application.

The CHR library includes a compiler, which translates CHR programs into Prolog programs on the fly, and a runtime system, which includes a stepper for debugging. Many constraint handlers are provided in the example directory of the library.

CHR are essentially a committed-choice language consisting of guarded rules that rewrite constraints into simpler ones until they are solved. CHR define both simplification of and propagation over constraints. Simplification replaces constraints by simpler constraints while preserving logical equivalence (e.g. X>Y,Y>X <=> fail). Propagation adds new constraints which are logically redundant but may cause further simplification (e.g. X>Y,Y>Z ==> X>Z). Repeatedly applying CHR incrementally simplifies and finally solves constraints (e.g. A>B,B>C,C>A leads to fail.

With multiple heads and propagation rules, CHR provide two features which are essential for non-trivial constraint handling. The declarative reading of CHR as formulas of first order logic allows one to reason about their correctness. On the other hand, regarding CHR as a rewrite system on logical formulas allows one to reason about their termination and confluence.

In case the implementation of CHR disagrees with your expectations based on this chapter, drop a line to the current maintainer: christian@ai.univie.ac.at (Christian Holzbaur).


Node:CHR Introductory Examples, Next:, Previous:CHR Introduction, Up:CHR

Introductory Examples

We define a CHR constraint for less-than-or-equal, leq, that can handle variable arguments. This handler can be found in the library as the file leq.pl. (The code works regardless of options switched on or off.)

:- use_module(library(chr)).

handler leq.
constraints leq/2.
:- op(500, xfx, leq).

reflexivity  @ X leq Y <=> X=Y | true.
antisymmetry @ X leq Y , Y leq X <=> X=Y.
idempotence  @ X leq Y \ X leq Y <=> true.
transitivity @ X leq Y , Y leq Z ==> X leq Z.

The CHR specify how leq simplifies and propagates as a constraint. They implement reflexivity, idempotence, antisymmetry and transitivity in a straightforward way. CHR reflexivity states that X leq Y simplifies to true, provided it is the case that X=Y. This test forms the (optional) guard of a rule, a precondition on the applicability of the rule. Hence, whenever we see a constraint of the form A leq A we can simplify it to true.

The rule antisymmetry means that if we find X leq Y as well as Y leq X in the constraint store, we can replace it by the logically equivalent X=Y. Note the different use of X=Y in the two rules: In the reflexivity rule the equality is a precondition (test) on the rule, while in the antisymmetry rule it is enforced when the rule fires. (The reflexivity rule could also have been written as reflexivity X leq X <=> true.)

The rules reflexivity and antisymmetry are simplification CHR. In such rules, the constraints found are removed when the rule applies and fires. The rule idempotence is a simpagation CHR, only the constraints right of '\' will be removed. The rule says that if we find X leq Y and another X leq Y in the constraint store, we can remove one.

Finally, the rule transitivity states that the conjunction X leq Y, Y leq Z implies X leq Z. Operationally, we add X leq Z as (redundant) constraint, without removing the constraints X leq Y, Y leq Z. This kind of CHR is called propagation CHR.

Propagation CHR are useful, as the query A leq B,C leq A,B leq C illustrates: The first two constraints cause CHR transitivity to fire and add C leq B to the query. This new constraint together with B leq C matches the head of CHR antisymmetry, X leq Y, Y leq X. So the two constraints are replaced by B=C. Since B=C makes B and C equivalent, CHR antisymmetry applies to the constraints A leq B, C leq A, resulting in A=B. The query contains no more CHR constraints, the simplification stops. The constraint handler we built has solved A leq B, C leq A, B leq C and produced the answer A=B, B=C:

A leq B,C leq A,B leq C.
% C leq A, A leq B propagates C leq B by transitivity.
% C leq B, B leq C simplifies to B=C by antisymmetry.
% A leq B, C leq A simplifies to A=B by antisymmetry since B=C.
A=B,B=C.

Note that multiple heads of rules are essential in solving these constraints. Also note that this handler implements a (partial) order constraint over any constraint domain, this generality is only possible with CHR.

As another example, we can implement the sieve of Eratosthenes to compute primes simply as (for variations see the handler primes.pl):

:- use_module(library(chr)).
handler eratosthenes.
constraints primes/1,prime/1.

primes(1) <=> true.
primes(N) <=> N>1 | M is N-1,prime(N),primes(M). % generate candidates

absorb(J) @ prime(I) \ prime(J) <=> J mod I =:= 0 | true.

The constraint primes(N) generates candidates for prime numbers, prime(M), where M is between 1 and N. The candidates react with each other such that each number absorbs multiples of itself. In the end, only prime numbers remain.

Looking at the two rules defining primes/1, note that head matching is used in CHR, so the first rule will only apply to primes(1). The test N>1 is a guard (precondition) on the second rule. A call with a free variable, like primes(X), will delay (suspend). The third, multi-headed rule absorb(J) reads as follows: If there is a constraint prime(I) and some other constraint prime(J) such that J mod I =:= 0 holds, i.e. J is a multiple of I, then keep prime(I) but remove prime(J) and execute the body of the rule, true.


Node:CHR Library, Next:, Previous:CHR Introductory Examples, Up:CHR

CHR Library

CHR extend the Prolog syntax by a few constructs introduced in the next sections. Technically, the extension is achieved through the user:term_expansion/2 mechanism. A file that contains a constraint handler may also contain arbitrary Prolog code. Constraint handling rules can be scattered across a file. Declarations and options should precede rules. There can only be at most one constraint handler per module.


Node:CHR Loading the Library, Next:, Previous:CHR Library, Up:CHR Library

Loading the Library

Before you can load or compile any file containing a constraint handler (solver) written in CHR, the chr library module has to be imported:

| ?- use_module(library(chr)).
It is recommended to include the corresponding directive at the start of your files containing handlers:
  :- use_module(library(chr)).


Node:CHR Declarations, Next:, Previous:CHR Loading the Library, Up:CHR Library

Declarations

Declarations in files containing CHR affect the compilation and thus the behavior of the rules at runtime.

The mandatory handler declaration precedes any other CHR specific code. Example:

handler minmax.
A handler name must be a valid Prolog atom. Per module, only one constraint handler can be defined.

The constraints must be declared before they are used by rules. With this mandatory declaration one lists the constraints the rules will later talk about. The declaration can be used more than once per handler. Example:

constraints  leq/2, minimum/3, maximum/3.

The following optional declaration allows for conditional rule compilation. Only the rules mentioned get compiled. Rules are referred to by their names (see CHR Syntax). The latest occurrence takes precedence if used more than once per handler. Although it can be put anywhere in the handler file, it makes sense, as with other declarations, to use it early. Example:

rules antisymmetry, transitivity.

To simplify the handling of operator declarations, in particular during fcompile/1, operator/3 declarations with the same denotation as op/3, but taking effect during compilation and loading, are helpful. Example:

operator(700, xfx, ::).
operator(600, xfx, :).


Node:CHR Syntax, Next:, Previous:CHR Declarations, Up:CHR Library

Constraint Handling Rules, Syntax

A constraint handling rule has one or more heads, an optional guard, a body and an optional name. A Head is a Constraint. A constraint is a callable Prolog term, whose functor is a declared constraint. The Guard is a Prolog goal. The Body of a rule is a Prolog goal (including constraints). A rule can be named with a Name which can be any Prolog term (including variables from the rule).

There are three kinds of constraint handling rules:

Rule           --> [Name @]
                     (Simplification | Propagation | Simpagation)
                        [pragma Pragma].

Simplification --> Heads         <=> [Guard '|'] Body
Propagation    --> Heads         ==> [Guard '|'] Body
Simpagation    --> Heads \ Heads <=> [Guard '|'] Body

Heads          --> Head | Head, Heads
Head           --> Constraint | Constraint # Id
Constraint     --> a callable term declared as constraint
Id             --> a unique variable

Guard          --> Ask | Ask & Tell
Ask            --> Goal
Tell           --> Goal
Goal           --> a callable term, including conjunction and disjunction etc.

Body           --> Goal

Pragma         --> a conjunction of terms usually referring to
                   one or more heads identified via #/2

The symbol | separates the guard (if present) from the body of a rule. Since | is read as ; (disjunction) by the reader, care has to be taken when using disjunction in the guard or body of the rule. The top level disjunction will always be interpreted as guard-body separator |, so proper bracketing has to be used, e.g. a <=> (b;c) | (d;e) instead of a <=> b;c | d;e and a <=> true | (d;e) instead of a <=> (d;e).

In simpagation rules, \ separates the heads of the rule into two parts.

Individual head constraints may be tagged with variables via #, which may be used as identifiers in pragma declarations, for example. Constraint identifiers must be distinct variables, not occurring elsewhere in the heads.

Guards test the applicability of a rule. Guards come in two parts, tell and ask, separated by &. If the & operator is not present, the whole guard is assumed to be of the ask type.

Declaratively, a rule relates heads and body provided the guard is true. A simplification rule means that the heads are true if and only if the body is true. A propagation rule means that the body is true if the heads are true. A simpagation rule combines a simplification and a propagation rule. The rule Heads1 \ Heads2 <=> Body is equivalent to the simplification rule Heads1, Heads2 <=> Heads1, Body. However, the simpagation rule is more compact to write, more efficient to execute and has better termination behavior than the corresponding simplification rule, since the constraints comprising Heads1 will not be removed and inserted again.


Node:How CHR work, Next:, Previous:CHR Syntax, Up:CHR Library

How CHR work

Each CHR constraint is associated with all rules in whose heads it occurs by the CHR compiler. Every time a CHR constraint is executed (called) or woken and reconsidered, it checks itself the applicability of its associated CHR by trying each CHR. By default, the rules are tried in textual order, i.e. in the order they occur in the defining file. To try a CHR, one of its heads is matched against the constraint. Matching succeeds if the constraint is an instance of the head. If a CHR has more than one head, the constraint store is searched for partner constraints that match the other heads. Heads are tried from left to right, except that in simpagation rules, the heads to be removed are tried before the head constraints to be kept (this is done for efficiency reasons). If the matching succeeds, the guard is executed. Otherwise the next rule is tried.

The guard either succeeds or fails. A guard succeeds if the execution of its Ask and Tell parts succeeds and in the ask part no variable that occurs also in the heads was touched or the cause of an instantiation error. The ask guard will fail otherwise. A variable is touched if it is unified with a term (including other variables from other constraints) different from itself. Tell guards, on the contrary, are trusted and not checked for that property. If the guard succeeds, the rule applies. Otherwise the next rule is tried.

If the firing CHR is a simplification rule, the matched constraints are removed from the store and the body of the CHR is executed. Similarly for a firing simpagation rule, except that the constraints that matched the heads preceding \ are kept. If the firing CHR is a propagation rule the body of the CHR is executed without removing any constraints. It is remembered that the propagation rule fired, so it will not fire again with the same constraints if the constraint is woken and reconsidered. If the currently active constraint has not been removed, the next rule is tried.

If the current constraint has not been removed and all rules have been tried, it delays until a variable occurring in the constraint is touched. Delaying means that the constraint is inserted into the constraint store. When a constraint is woken, all its rules are tried again. (This process can be watched and inspected with the CHR debugger, see below.)


Node:CHR Pragmas, Next:, Previous:How CHR work, Up:CHR Library

Pragmas

Pragmas are annotations to rules and constraints that enable the compiler to generate more specific, more optimized code. A pragma can be a conjunction of the following terms:


already_in_heads
The intention of simplification and simpagation rules is often to combine the heads into a stronger version of one of them. Depending on the strength of the guard, the new constraint may be identical to one of the heads to removed by the rule. This removal followed by addition is inefficient and may even cause termination problems. If the pragma is used, this situation is detected and the corresponding problems are avoided. The pragma applies to all constraints removed by the rule.
already_in_head(Id)
Shares the intention of the previous pragma, but affects only the constraint indicated via Id. Note that one can use more than one pragma per rule.
passive(Id)
No code will be generated for the specified constraint in the particular head position. This means that the constraint will not see the rule, it is passive in that rule. This changes the behavior of the CHR system, because normally, a rule can be entered starting from each head constraint. Usually this pragma will improve the efficiency of the constraint handler, but care has to be taken in order not to lose completeness.

For example, in the handler leq, any pair of constraints, say A leq B, B leq A, that matches the head X leq Y , Y leq X of the antisymmetry rule, will also match it when the constraints are exchanged, B leq A, A leq B. Therefore it is enough if a currently active constraint enters this rule in the first head only, the second head can be declared to be passive. Similarly for the idempotence rule. For this rule, it is more efficient to declare the first head passive, so that the currently active constraint will be removed when the rule fires (instead of removing the older constraint and redoing all the propagation with the currently active constraint). Note that the compiler itself detects the symmetry of the two head constraints in the simplification rule antisymmetry, thus it is automatically declared passive and the compiler outputs CHR eliminated code for head 2 in antisymmetry.

antisymmetry  X leq Y , Y leq X # Id <=> X=Y pragma passive(Id).
idempotence   X leq Y # Id \ X leq Y <=> true pragma passive(Id).
transitivity  X leq Y # Id , Y leq Z ==> X leq Z pragma passive(Id).
Declaring the first head of rule transitivity passive changes the behavior of the handler. It will propagate less depending on the order in which the constraints arrive:
?- X leq Y, Y leq Z.
X leq Y,
Y leq Z,
X leq Z ?

?- Y leq Z, X leq Y.
Y leq Z,
X leq Y ?

?- Y leq Z, X leq Y, Z leq X.
Y = X,
Z = X ?
The last query shows that the handler is still complete in the sense that all circular chains of leq-relations are collapsed into equalities.


Node:CHR Options, Next:, Previous:CHR Pragmas, Up:CHR Library

Options

Options parametrise the rule compilation process. Thus they should precede the rule definitions. Example:

option(check_guard_bindings, off).

The format below lists the names of the recognized options together with the acceptable values. The first entry in the lists is the default value.


option(debug_compile, [off,on]).
Instruments the generated code such that the execution of the rules may be traced (see CHR Debugging).
option(check_guard_bindings, [on,off]).
Per default, for guards of type ask the CHR runtime system makes sure that no variables are touched or the cause of an instantiation error. These checks may be turned off with this option, i.e. all guards are treated as if they were of the tell variety. The option was kept for backward compatibility. Tell and ask guards offer better granularity.
option(already_in_store, [off,on]).
If this option is on, the CHR runtime system checks for the presence of an identical constraint upon the insertion into the store. If present, the attempted insertion has no effect. Since checking for duplicates for all constraints costs, duplicate removal specific to individual constraints, using a few simpagation rules of the following form instead, may be a better solution.
Constraint \ Constraint <=> true.

option(already_in_heads, [off,on]).
The intention of simplification and simpagation rules is often to combine the heads into a stronger version of one of them. Depending on the strength of the guard, the new constraint may be identical to one of the heads removed by the rule. This removal followed by addition is inefficient and may even cause termination problems. If the option is enabled, this situation is detected and the corresponding problems are avoided. This option applies to all constraints and is provided mainly for backward compatibility. Better grained control can be achieved with corresponding pragmas. (see CHR Pragmas).

The remaining options are meant for CHR implementors only:

option(flatten, [on,off]).
option(rule_ordering, [canonical,heuristic]).
option(simpagation_scheme, [single,multi]).
option(revive_scheme, [new,old]).
option(dead_code_elimination, [on,off]).


Node:CHR Built-In Predicates, Next:, Previous:CHR Options, Up:CHR Library

Built-In Predicates

This table lists the predicates made available by the CHR library. They are meant for advanced users, who want to tailor the CHR system towards their specific needs.

current_handler(?Handler, ?Module)

Non-deterministically enumerates the defined handlers with the module they are defined in.

current_constraint(?Handler, ?Constraint)

Non-deterministically enumerates the defined constraints in the form Functor/Arity and the handlers they are defined in.

insert_constraint(+Constraint, -Id)

Inserts Constraint into the constraint store without executing any rules. The constraint will be woken and reconsidered when one of the variables in Constraint is touched. Id is unified with an internal object representing the constraint. This predicate only gets defined when a handler and constraints are declared (see CHR Declarations).

insert_constraint(+Constraint, -Id, ?Term)

Inserts Constraint into the constraint store without executing any rules. The constraint will be woken and reconsidered when one of the variables in Term is touched. Id is unified with an internal object representing the constraint. This predicate only gets defined when a handler and constraints are declared (see CHR Declarations).

find_constraint(?Pattern, -Id)

Non-deterministically enumerates constraints from the constraint store that match Pattern, i.e. which are instances of Pattern. Id is unified with an internal object representing the constraint.

find_constraint(-Var, ?Pattern, -Id)

Non-deterministically enumerates constraints from the constraint store that delay on Var and match Pattern, i.e. which are instances of Pattern. The identifier Id can be used to refer to the constraint later, e.g. for removal.

findall_constraints(?Pattern, ?List)

Unifies List with a list of Constraint # Id pairs from the constraint store that match Pattern.

findall_constraints(-Var, ?Pattern, ?List)

Unifies List with a list of Constraint # Id pairs from the constraint store that delay on Var and match Pattern.

remove_constraint(+Id)

Removes the constraint Id, obtained with one of the previous predicates, from the constraint store.

unconstrained(?Var)

Succeeds if no CHR constraint delays on Var. Defined as:

unconstrained(X) :-
    find_constraint(X, _, _), !, fail.
unconstrained(_).

notify_constrained(?Var)

Leads to the reconsideration of the constraints associated with Var. This mechanism allows solvers to communicate reductions on the set of possible values of variables prior to making bindings.


Node:CHR Consulting and Compiling, Next:, Previous:CHR Built-In Predicates, Up:CHR Library

Consulting and Compiling Constraint Handlers

The CHR compilation process has been made as transparent as possible. The user deals with files containing CHR just as with files containing ordinary Prolog predicates. Thus CHR may be consulted, compiled with various compilation modes, and compiled to file (see Load Intro).


Node:CHR Compiler-generated Predicates, Next:, Previous:CHR Consulting and Compiling, Up:CHR Library

Compiler-generated Predicates

Besides predicates for the defined constraints, the CHR compiler generates some support predicates in the module containing the handler. To avoid naming conflicts, the following predicates must not be defined or referred to by user code in the same module:

verify_attributes/3
attribute_goal/2
attach_increment/2
'attach_F/A'/2
for every defined constraint F/A.
'F/A_N_M_...'/Arity
for every defined constraint F/A. N,M is are integers, Arity > A.

For the prime number example that is:

        attach_increment/2
        attach_prime/1/2
        attach_primes/1/2
        attribute_goal/2
        goal_expansion/3
        prime/1
        prime/1_1/2
        prime/1_1_0/3
        prime/1_2/2
        primes/1
        primes/1_1/2
        verify_attributes/3

If an author of a handler wants to avoid naming conflicts with the code that uses the handler, it is easy to encapsulate the handler. The module declaration below puts the handler into module primes, which exports only selected predicates - the constraints in our example.

        :- module(primes, [primes/1,prime/1]).

        :- use_module(library(chr)).

        handler eratosthenes.
        constraints primes/1,prime/1.
        ...


Node:CHR Operator Declarations, Next:, Previous:CHR Compiler-generated Predicates, Up:CHR Library

Operator Declarations

This table lists the operators as used by the CHR library:

:- op(1200, xfx, @).
:- op(1190, xfx, pragma).
:- op(1180, xfx, [==>,<=>]).
:- op(1180, fy,  chr_spy).
:- op(1180, fy,  chr_nospy).
:- op(1150, fx,  handler).
:- op(1150, fx,  constraints).
:- op(1150, fx,  rules).
:- op(1100, xfx, '|').
:- op(1100, xfx, \ ).
:- op(1050, xfx, &).
:- op( 500, yfx, #).


Node:CHR Exceptions, Previous:CHR Operator Declarations, Up:CHR Library

Exceptions

The CHR runtime system reports instantiation and type errors for the predicates:

find_constraint/2
findall_constraints/3
insert_constraint/2
remove_constraint/1
notify_constrained/1

The only other CHR specific runtime error is:

{CHR ERROR: registering <New>, module <Module> already hosts <Old>}
An attempt to load a second handler New into module <Module> already hosting handler <Old> was made.

The following exceptional conditions are detected by the CHR compiler:

{CHR Compiler ERROR: syntax rule <N>: <Term>}
If the N-th <Term> in the file being loaded violates the CHR syntax (see CHR Syntax).
{CHR Compiler ERROR: too many general heads in <Name>}
Unspecific heads in definitions like C \ C <=> true must not be combined with other heads in rule <Name>.
{CHR Compiler ERROR: bad pragma <Pragma> in <Name>}
The pragma <Pragma> used in rule <Name> does not qualify. Currently this only happens if <Pragma> is unbound.
{CHR Compiler ERROR: found head <F/A> in <Name>, expected one of: <F/A list>}
Rule <Name> has a head of given F/A which is not among the defined constraints.
{CHR Compiler ERROR: head identifiers in <Name> are not unique variables}
The identifiers to refer to individual constraints (heads) via # in rule <Name> do not meet the indicated requirements.
{CHR Compiler ERROR: no handler defined}
CHR specific language elements, declarations or rules for example, are used before a handler was defined. This error is usually reported a couple of times, i.e. as often as there are CHR forms in the file expecting the missing definition.
{CHR Compiler ERROR: compilation failed}
Not your fault. Send us a bug report.


Node:CHR Debugging, Next:, Previous:CHR Library, Up:CHR

Debugging CHR Programs

Use option(debug_compile,on) preceding any rules in the file containing the handler to enable CHR debugging. The CHR debugging mechanism works by instrumenting the code generated by the CHR compiler. Basically, the CHR debugger works like the Prolog debugger. The main differences are: there are extra ports specific to CHR, and the CHR debugger provides no means for the user to change the flow of control, i.e. there are currently no retry and fail options available.


Node:CHR Control Flow Model, Next:, Previous:CHR Debugging, Up:CHR Debugging

Control Flow Model

The entities reflected by the CHR debugger are constraints and rules. Constraints are treated like ordinary Prolog goals with the usual ports: [call,exit,redo,fail]. In addition, constraints may get inserted into or removed from the constraint store (ports: insert,remove), and stored constraints containing variables will be woken and reconsidered (port: wake) when variables are touched.

The execution of a constraint consists of trying to apply the rules mentioning the constraint in their heads. Two ports for rules reflect this process: At a try port the active constraint matches one of the heads of the rule, and matching constraints for the remaining heads of the rule, if any, have been found as well. The transition from a try port to an apply port takes place when the guard has been successfully evaluated, i.e. when the rule commits. At the apply port, the body of the rule is just about to be executed. The body is a Prolog goal transparent to the CHR debugger. If the rule body contains CHR constraints, the CHR debugger will track them again. If the rules were consulted, the Prolog debugger can be used to study the evaluations of the other predicates in the body.


Node:CHR Debugging Predicates, Next:, Previous:CHR Control Flow Model, Up:CHR Debugging

CHR Debugging Predicates

The following predicates control the operation of the CHR debugger:

chr_trace

Switches the CHR debugger on and ensures that the next time control enters a CHR port, a message will be produced and you will be asked to interact.

At this point you have a number of options. See CHR Debugging Options. In particular, you can just type <cr> (Return) to creep (or single-step) into your program. You will notice that the CHR debugger stops at many ports. If this is not what you want, the predicate chr_leash gives full control over the ports at which you are prompted.

chr_debug

Switches the CHR debugger on and ensures that the next time control enters a CHR port with a spypoint set, a message will be produced and you will be asked to interact.

chr_nodebug

Switches the CHR debugger off. If there are any spypoints set then they will be kept.

chr_notrace

Equivalent to chr_nodebug.

chr_debugging

Prints onto the standard error stream information about the current CHR debugging state. This will show:

  1. Whether the CHR debugger is switched on.
  2. What spypoints have been set (see below).
  3. What mode of leashing is in force (see below).

chr_leash(+Mode)

The leashing mode is set to Mode. It determines the CHR ports at which you are to be prompted when you creep through your program. At unleashed ports a tracing message is still output, but program execution does not stop to allow user interaction. Note that the ports of spypoints are always leashed (and cannot be unleashed). Mode is a list containing none, one or more of the following port names:

call
Prompt when a constraint is executed for the first time.
exit
Prompt when the constraint is successfully processed, i.e. the applicable rules have applied.
redo
Prompt at subsequent exits generated by non-determinate rule bodies.
fail
Prompt when a constraint fails.
wake
Prompt when a constraint from the constraint store is woken and reconsidered because one of its variables has been touched.
try
Prompt just before the guard evaluation of a rule, after constraints matching the heads have been found.
apply
Prompt upon the application of a rule, after the successful guard evaluation, when the rule commits and fires, just before evaluating the body.
insert
Prompt when a constraint gets inserted into the constraint store, i.e. after all rules have been tried.
remove
Prompt when a constraint gets removed from the constraint store, e.g. when a simplification rule applies.

The initial value of the CHR leashing mode is [call,exit,fail,wake,apply]. Predefined shortcuts are:

chr_leash(none), chr_leash(off)
To turn leashing off.
chr_leash(all)
To prompt at every port.
chr_leash(default)
Same as chr_leash([call,exit,fail,wake,apply]).
chr_leash(call)
No need to use a list if only a singular port is to be leashed.


Node:CHR spypoints, Next:, Previous:CHR Debugging Predicates, Up:CHR Debugging

CHR spypoints

For CHR programs of any size, it is clearly impractical to creep through the entire program. Spypoints make it possible to stop the program upon an event of interest. Once there, one can set further spypoints in order to catch the control flow a bit further on, or one can start creeping.

Setting a spypoint on a constraint or a rule indicates that you wish to see all control flow through the various ports involved, except during skips. When control passes through any port with a spypoint set on it, a message is output and the user is asked to interact. Note that the current mode of leashing does not affect spypoints: user interaction is requested on every port.

Spypoints are set and removed by the following predicates, which are declared as prefix operators:

chr_spy Spec

Sets spypoints on constraints and rules given by Spec, which is is of the form:

_ (variable)
denoting all constraints and rules, or:
constraints Cs
where Cs is one of

_ (variable)
denoting all constraints
C,...,C
denoting a list of constraints C
Name
denoting all constraints with this functor, regardless of arity
Name/Arity
denoting the constraint of that name and arity

rules Rs
where Rs is one of:

_ (variable)
denoting all rules
R,...,R
denoting a list of rules R
Name
where Name is the name of a rule in any handler.
already_in_store
The name of a rule implicitly defined by the system when the option already_in_store is in effect.
already_in_heads
The name of a rule implicitly defined by the system when the option already_in_heads or the corresponding pragmas are in effect.
Handler:Name
where Handler is the name of a constraint handler and Name is the name of a rule in that handler

Examples:

| ?- chr_spy rules rule(3), transitivity, already_in_store.
| ?- chr_spy constraints prime/1.

If you set spypoints, the CHR debugger will be switched on.

chr_nospy Spec

Removes spypoints on constraints and rules given by Spec, where Spec is of the form as described for chr_spy Spec. There is no chr_nospyall/0. To remove all CHR spypoints use chr_nospy _.

The options available when you arrive at a spypoint are described later. See CHR Debugging Options.


Node:CHR Debugging Messages, Next:, Previous:CHR spypoints, Up:CHR Debugging

CHR Debugging Messages

All trace messages are output to the standard error stream. This allows you to trace programs while they are performing file I/O. The basic format is as follows:

S 3   1 try     eratosthenes:absorb(10) @ prime(9)#<c4>, prime(10)#<c2> ?

S is a spypoint indicator. It is printed as if there is no spypoint, as r, indicating that there is a spypoint on this rule, or as c if one of the involved constraints has a spypoint.

The first number indicates the current depth of the execution; i.e. the number of direct ancestors the currently active constraint has.

The second number indicates the head position of the currently active constraint at rule ports.

The next item tells you which port is currently traced.

A constraint or a matching rule are printed next. Constraints print as Term#Id, where Id is a unique identifier pointing into the constraint store. Rules are printed as Handler:Name @, followed by the constraints matching the heads.

The final ? is the prompt indicating that you should type in one of the debug options (see CHR Debugging Options).


Node:CHR Debugging Options, Previous:CHR Debugging Messages, Up:CHR Debugging

CHR Debugging Options

This section describes the options available when the system prompts you after printing out a debugging message. Most of them you know from the standard Prolog debugger. All the options are one letter mnemonics, some of which can be optionally followed by a decimal integer. They are read from the standard input stream up to the end of the line (Return, <<cr>>). Blanks will be ignored.

The only option which you really have to remember is h. This provides help in the form of the following list of available options.

CHR debugging options:
   <cr>   creep            c      creep
    l     leap
    s     skip             s <i>  skip (ancestor i)
    g     ancestors
    &     constraints      & <i>  constraints (details)
    n     nodebug          =      debugging
    +     spy this
    -     nospy this       .      show rule
    <     reset printdepth < <n>  set printdepth
    a     abort            b      break
    ?     help             h      help
c
<<cr>>
creep causes the debugger to single-step to the very next port and print a message. Then if the port is leashed, the user is prompted for further interaction. Otherwise, it continues creeping. If leashing is off, creep is the same as leap (see below) except that a complete trace is printed on the standard error stream.
l
leap causes the debugger to resume running your program, only stopping when a spypoint is reached (or when the program terminates). Leaping can thus be used to follow the execution at a higher level than exhaustive tracing.
s
s i
skip over the entire execution of the constraint. That is, you will not see anything until control comes back to this constraint (at either the exit port or the fail port). This includes ports with spypoints set; they will be masked out during the skip. The command can be used with a numeric argument to skip the execution up to and including the ancestor indicated by the argument. Example:
      ...
      4   - exit    prime(8)#<c6> ? g
Ancestors:
      1   1 apply   eratosthenes:rule(2) @ primes(10)#<c1>
      2   1 apply   eratosthenes:rule(2) @ primes(9)#<c3>
      3   1 apply   eratosthenes:rule(2) @ primes(8)#<c5>
      4   - call    prime(8)#<c6>

      4   - exit    prime(8)#<c6> ? s 2
      2   - exit    primes(9)#<c3> ?

g
print ancestors provides you with a list of ancestors to the currently active constraint, i.e. all constraints not yet exited that led to the current constraint in the derivation sequence. The format is the same as with trace messages. Constraints start with call entries in the stack. The subsequent application of a rule replaces the call entry in the stack with an apply entry. Later the constraint shows again as redo or fail entry. Example:
      0   - call    primes(10)#<c1> ?
      1   1 try     eratosthenes:rule(2) @ primes(10)#<c1> ? g

Ancestors:
      1   - call    primes(10)#<c1>

      1   1 try     eratosthenes:rule(2) @ primes(10)#<c1> ?
      1   1 apply   eratosthenes:rule(2) @ primes(10)#<c1> ?
      1   - call    prime(10)#<c2> ?
      2   - insert  prime(10)#<c2>
      2   - exit    prime(10)#<c2> ? g

Ancestors:
      1   1 apply   eratosthenes:rule(2) @ primes(10)#<c1>
      2   - call    prime(10)#<c2>

&
print constraints prints a list of the constraints in the constraint store. With a numeric argument, details relevant primarily to CHR implementors are shown.
n
nodebug switches the CHR debugger off.
=
debugging outputs information concerning the status of the CHR debugger as via chr_debugging/0
+
spy this sets a spypoint on the current constraint or rule.
-
nospy this removes the spypoint from the current constraint or rule, if it exists.
.
show rule prints the current rule instantiated by the matched constraints. Example:
 8   1 apply   era:absorb(8) @ prime(4)#<c14> \ prime(8)#<c6> ? .

 absorb(8) @
  prime(4)#<c14> \
    prime(8)#<c6> <=>

    8 mod 4=:=0
    |
    true.

<
< n
While in the debugger, a printdepth is in effect for limiting the subterm nesting level when printing rules and constraints. The limit is initially 10. This command, without arguments, resets the limit to 10. With an argument of n, the limit is set to n, treating 0 as infinity.
a
abort calls the built-in predicate abort/0.
b
break calls the built-in predicate break/0, thus putting you at a recursive top-level. When you end the break (entering ^D) you will be re-prompted at the port at which you broke. The CHR debugger is temporarily switched off as you call the break and will be switched on again when you finish the break and go back to the old execution. Any changes to the CHR leashing or to spypoints during the break will remain in effect.
?
h
help displays the table of options given above.


Node:CHR Programming Hints, Next:, Previous:CHR Debugging, Up:CHR

Programming Hints

This section gives you some programming hints for CHR. For maximum efficiency of your constraint handler, see also the previous subsections on declarations and options.

Constraint handling rules for a given constraint system can often be derived from its definition in formalisms such as inference rules, rewrite rules, sequents, formulas expressing axioms and theorems. CHR can also be found by first considering special cases of each constraint and then looking at interactions of pairs of constraints sharing a variable. Cases that do not occur in the application can be ignored.

It is important to find the right granularity of the constraints. Assume one wants to express that n variables are different from each other. It is more efficient to have a single constraint all_different(List_of_n_Vars) than n*n inequality constraints between each pair of different variables. However, the extreme case of having a single constraint modeling the whole constraint store will usually be inefficient.

Starting from an executable specification, the rules can then be refined and adapted to the specifics of the application. Efficiency can be improved by weakening the guards to perform simplification as early as needed and by strengthening the guards to do the just right amount of propagation. Propagation rules can be expensive, because no constraints are removed.

The more heads a rule has, the more expensive it is. Rules with several heads are more efficient, if the heads of the rule share a variable (which is usually the case). Then the search for a partner constraint has to consider less candidates. In the current implementation, constraints are indexed by their functors, so that the search is only performed among the constraints containing the shared variable. Moreover, two rules with identical (or sufficiently similar) heads can be merged into one rule so that the search for a partner constraint is only performed once instead of twice.

As guards are tried frequently, they should be simple tests not involving side-effects. Head matching is more efficient than explicitly checking equalities in the ask-part of the guard. In the tell part of a guard, it should be made sure that variables from the head are never touched (e.g. by using nonvar or ground if necessary). For efficiency and clarity reasons, one should also avoid using constraints in guards. Besides conjunctions, disjunctions are allowed in the guard, but they should be used with care. The use of other control built-in predicates in the guard is discouraged. Negation and if-then-else in the ask part of a guard can give wrong results, since e.g. failure of the negated goal may be due to touching its variables.

Several handlers can be used simultaneously if they do not share constraints with the same name. The implementation will not work correctly if the same constraint is defined in rules of different handlers that have been compiled separately. In such a case, the handlers must be merged by hand. This means that the source code has to be edited so that the rules for the shared constraint are together (in one module). Changes may be necessary (like strengthening guards) to avoid divergence or loops in the computation.


Node:CHR Constraint Handlers, Next:, Previous:CHR Programming Hints, Up:CHR

Constraint Handlers

The CHR library comes with plenty of constraint handlers written in CHR. The most recent versions of these are maintained at:

http://www.pst.informatik.uni-muenchen.de/~fruehwir/chr-solver.html

arc.pl
classical arc-consistency over finite domains
bool.pl
simple Boolean constraints
cft.pl
feature term constraints according to the CFT theory
domain.pl
finite domains over arbitrary ground terms and interval domains over integers and reals, but without arithmetic functions
gcd.pl
elegant two-liner for the greatest common divisor
interval.pl
straightforward interval domains over integers and reals, with arithmetic functions
kl-one.pl
terminological reasoning similar to KL-ONE or feature trees
leq.pl
standard introductory CHR example handler for less-than-or-equal
list.pl
equality constraints over concatenations of lists (or strings)
listdom.pl
a straightforward finite enumeration list domains over integers, similar to interval.pl
math-elim.pl
solves linear polynomial equations and inequations using variable elimination, several variations possible
math-fougau.pl
solves linear polynomial equations and inequations by combining variable elimination for equations with Fourier's algorithm for inequations, several variations possible
math-fourier.pl
a straightforward Fouriers algorithm to solve polynomial inequations over the real or rational numbers
math-gauss.pl
a straightforward, elegant implementation of variable elimination for equations in one rule
minmax.pl
simple less-than and less-than-or-equal ordering constraints together with minimum and maximum constraints
modelgenerator.pl
example of how to use CHR for model generation in theorem proving
monkey.pl
classical monkey and banana problem, illustrates how CHR can be used as a fairly efficient production rule system
osf.pl
constraints over order sorted feature terms according to the OSF theory
oztype.pl
rational trees with disequality and OZ type constraint with intersection
pathc.pl
the most simple example of a handler for path consistency - two rules
primes.pl
elegant implementations of the sieve of Eratosthenes reminiscent of the chemical abstract machine model, also illustrates use of CHR as a general purpose concurrent constraint language
scheduling.pl
simple classical constraint logic programming scheduling example on building a house
tarski.pl
most of Tarski's axiomatization of geometry as constraint system
term.pl
Prolog term manipulation built-in predicates functor/3, arg/3, =../2 as constraints
time-pc.pl
grand generic handler for path-consistency over arbitrary constraints, load via time.pl to get a powerful solver for temporal constraints based on Meiri's unifying framework. time-rnd.pl contains a generator for random test problems.
time-point.pl
quantitative temporal constraints over time points using path-consistency
tree.pl
equality and disequality over finite and infinite trees (terms)
type.pl
equalities and type constraints over finite and infinite trees (terms)

You can consult or compile a constraint handler from the CHR library using e.g.:

?- [library('chr/examples/gcd')].
?- compile(library('chr/examples/gcd')).
If you want to learn more about the handlers, look at their documented source code.

In addition, there are files with example queries for some handlers, their file name starts with examples- and the file extension indicates the handler, e.g. .bool:

examples-adder.bool
examples-benchmark.math
examples-deussen.bool
examples-diaz.bool
examples-fourier.math
examples-holzbaur.math
examples-lim1.math
examples-lim2.math
examples-lim3.math
examples-puzzle.bool
examples-queens.bool
examples-queens.domain
examples-stuckey.math
examples-thom.math


Node:CHR Backward Compatibility, Previous:CHR Constraint Handlers, Up:CHR

Backward Compatibility

In this section, we discuss backward compatibility with the CHR library of Eclipse Prolog.

  1. The restriction on at most two heads in a rule has been abandoned. A rule can have as many heads as you like. Note however, that searching for partner constraints can be expensive.
  2. By default, rules are compiled in textual order. This gives the programmer more control over the constraint handling process. In the Eclipse library of CHR, the compiler was optimizing the order of rules. Therefore, when porting a handler, rules may have to be reordered. A good heuristic is to prefer simplification to simpagation and propagation and to prefer rules with single heads to rules with several heads. Instead of manually rearranging an old handler one may also use the following combination of options to get the corresponding effect:
    option(rule_ordering,heuristic).
    option(revive_scheme,old).
    
  3. For backward compatibility, the already_in_store, already_in_head and guard_bindings options are still around, but there are CHR syntax extensions: CHR Syntax and pragmas CHR Pragmas offering better grained control.
  4. The Eclipse library of CHR provided automatic built-in labeling through the label_with declaration. Since it was not widely used and can be easily simulated, built-in labeling was dropped. The same effect can be achieved by replacing the declaration label_with Constraint if Guard by the simplification rule chr_labeling, Constraint <=> Guard | Constraint', chr_labeling and by renaming the head in each clause Constraint :- Body into Constraint' :- Body where Constraint' is a new predicate. Efficiency can be improved by declaring Constraint to be passive: chr_labeling, Constraint#Id <=> Guard | Constraint', chr_labeling pragma passive(Id). This translation will not work if option(already_in_heads,on). In that case use e.g. chr_labeling(_), Constraint <=> Guard | Constraint', chr_labeling(_) to make the new call to chr_labeling differ from the head occurrence.
  5. The set of built-in predicates for advanced CHR users is now larger and better designed. Also the debugger has been improved. The Opium debugging environment is not available in SICStus Prolog.


Node:Obj Intro, Next:, Previous:CHR, Up:Top

SICStus Objects

SICStus Objects is an extension to SICStus Prolog for flexible structuring, sharing and reuse of knowledge in large logic programming applications. It enhances Prolog with an expressive and efficient object-oriented programming component.

SICStus Objects is based on the notion of prototypes. In object-oriented programming a prototype is an object that represents a typical behavior of a certain concept. A prototype can be used as is or as a model to construct other objects that share some of the characteristics of the prototypical object. These specialized objects can themselves become prototypes used to construct other objects and so forth. The basic mechanism for sharing is by inheritance and delegation. Inheritance is known for most readers. By using the delegation mechanism an object can forward a message to another object to invoke a method defined by the recipient but interpreted in the context of the sender.

In SICStus Objects, an object is a named collection of predicate definitions. In this sense an object is similar to a Prolog module. The object system can be seen as an extension of SICStus Prolog's module system. In addition an object may have attributes that are modifiable. Predicate definitions belonging to an object are called methods. So, an object is conceptually a named collection of methods and attributes. Some of the methods defined for an object need not be stored explicitly within the object, but are rather shared with other objects by the inheritance mechanism.

The Object system allows objects to be defined in a file, or dynamically created during the execution of a program. Objects defined in a file are integrated into SICStus Prolog in a way similar to definite clause grammars. That is to say, objects have a specific syntax as Prolog terms, and can be loaded and expanded into Prolog code. When an object is created, during load-time, or run-time, it inherits the methods and attributes of its prototypical object(s). Objects defined in a file can be either static or dynamic. Also, methods can be either dynamic or static. these properties are inherited by sub-objects. Objects created during execution are dynamic.

The inheritance mechanism is implemented using the importation mechanism of the module system. The default inheritance is an inheritance by overriding mechanism, which means that if a method is defined locally, and the same method is defined in a super-object, then the clauses of the super-method are not part of the definition of the local one. As usual in Prolog, methods can be non-determinately defined, and alternative answers can be retrieved through backtracking. Using the delegation mechanism, other methods for knowledge sharing can be implemented by the user. In SICStus Objects, there is an initial prototypical proto-object called object, from which other objects may be constructed, directly or indirectly.


Node:Obj Getting Started, Next:, Previous:Obj Intro, Up:Obj Intro

Getting Started

To load the SICStus Objects library, enter the query:

| ?- use_module(library(objects)).

SICStus Objects defines some new infix and prefix operators, and redefines some of the built-in ones. The following operators become installed:

:- op(1200, xfy, [ & ]).
:- op(1198, xfx, [ :- ]).
:- op(1198,  fx, [ :- ]).
:- op(550,  xfx, [ ::, <: ]).
:- op(550,   fx, [ ::, <: ]).


Node:Obj Declared Objects, Next:, Previous:Obj Getting Started, Up:Obj Intro

Declared Objects

Declared objects are created when the files defining them are loaded into the system.


Node:Object Declaration, Next:, Previous:Obj Declared Objects, Up:Obj Declared Objects

Object Declaration

An object object-identifier is declared by writing it in the following form:

object-identifier :: {
        sentence-1 &
        sentence-2 &
        :
        sentence-n
        }.

where object-identifier is a Prolog term that is either an atom or a compound term of the form functor(V1,...,Vn), where V1,...,Vn are distinct variables. The object body consists of a number of sentences, possibly none, surrounded by braces, where each sentence is either a method-directive, to be executed when the object is created, or a method-clause. A method is a number of method-clauses with the same principal functor. A method-clause has a clausal syntax similar to that of Prolog, but instead of usual predicate calls in the body of a clause there are method-calls. Ordinary Prolog goals are also allowed in a prefixed form, using : as a prefix. A method-directive is a directive which contains method-calls.

All sentences are subject to term expansion (see Definite, built-in expand_term/2) before further processing, so in particular definite clause grammar syntax can be used in method-clauses. In addition, before expand_term/2, sentences are expanded by the predicate user:method_expansion/3.

method_expansion(+Term1,+ObjectIdentifier,?Term2) [Hook]
user:method_expansion(+Term1,+ObjectIdentifier,?Term2)

Defines transformations on methods similarly as user:term_expansion/[2,4]. At the end of an object definition, user:method_expansion/3 is called with end_of_object.


Node:Method Declarations, Next:, Previous:Object Declaration, Up:Obj Declared Objects

Method Declarations

Method-clauses are declared similarly to Prolog clauses. Thus a method-clause can be either a unit-clause or a rule. We also allow a default catch-all method-clause as the last clause in an object body. The catch-all clause has as its head a Prolog variable, in order to match messages that are not previously defined or inherited in the object. It can be used to implement alternative inheritance mechanisms.

Goals in the body of a rule have the normal control structures of Prolog:

:P, :Q
Conjunction
:P; :Q
Disjunction
!
Cut
\+ :P
Negation
:P -> :Q
:P -> :Q; :R
if(:P, :Q, :R)
If-then[-else]
?A = ?B
Unification

Atomic goals in the body of a method-clause may be one of the following:

:goal
to call the Prolog predicate goal in the source module.
m:goal
to call the Prolog predicate goal in module m.
goal
to send the message goal to the object Self.
::goal
to send the message goal to a method that may be defined locally or inherited by the object.
<:goal
to delegate the message goal to a method that may be defined locally or inherited by the object.
object::goal
to send the message goal to object object.
object<:goal
to delegate the message goal to object object.

Message sending and delegation will be explained later (see Obj Self).

The following is a definition for the object list_object. It is constructed from three methods: append/3, member/2, and length/2. Note that the calls to append/3 and length/2 are to the local definition, whereas the member/2 call is to the predicate imported from the Prolog library module lists.

list_object :: {
        :- :use_module(library(lists), [append/3,member/2]) &

        append([], L, L) &
        append([X|L1], L2, [X|L3]) :-
                :: append(L1, L2, L3) &

        member(X, L) :-
                :member(X,L) &

        length([], 0) &
        length([_|L], N) :-
                :: length(L, N1),
                :(N is N1+1)
        }.

The following object apt_1 could be part of a larger database about free apartments in a real-estate agency:

apt_1 :: {
        super(apartment) &

        street_name('York') &
        street_number(100) &
        wall_color(white) &
        floor_surface(wood)
        }.

Another way to define apt_1 is by using attributes. These can be retrieved and modified efficiently by the methods get/1 and set/1 respectively.

apt_1 :: {
        super(apartment) &

        attributes([
               street_name('York'),
               street_number(100),
               wall_color(white),
               floor_surface(wood)])
        }.


Node:Generic Objects for Easy Reuse, Previous:Method Declarations, Up:Obj Declared Objects

Generic Objects for Easy Reuse

Defining objects for easy reuse is a very important property for reducing the cost of large projects. One important technique is to define prototypes in a parameterized way, so that various instantiations of a prototype correspond to different uses. Parameterized or generic objects have been used for this purpose in other object-oriented systems. An object-identifier can be a compound term. The arguments of the term are parameters that are visible in the object-body. Here we show one example. Other examples and techniques that use this facility has been investigated extensively in [McCabe 92].

The following is an object sort that sorts lists of different types. sort has a parameter that defines the type of the elements of the list. Notice that Type is visible to all methods in the body of sort, and is used in the method partition/4. In the query, we use sort(rat) to sort a list of terms denoting rational numbers. We must therefore define a rat object and its < method also:

rat :: {
        (P/Q < R/S) :- :(P*S < Q*R)
        }.

sort(Type) :: {
        :- :use_module(library(lists), [append/3]) &

        qsort([], []) &
        qsort([P|L], S) :-
                partition(L, P, Small, Large),
                qsort(Small, S0),
                qsort(Large, S1),
                :append(S0, [P|S1], S) &

        partition([], _P, [], []) &
        partition([X|L1], P, Small, Large) :-
                (   Type :: (X < P) ->
                    Small = [X|Small1], Large = Large1
                ;   Small = Small1, Large = [X|Large1]
                ),
                partition(L1, P, Small1, Large1)
        }.

| ?- sort(rat) :: qsort([23/3, 34/11, 45/17], L).

L = [45/17,34/11,23/3]

Parameterized objects are interesting in their own right in Prolog even if one is not interested in the object-oriented paradigm. They provide global context variables in a Prolog program without having to add such variables as additional context arguments to each clause that potentially uses the context.


Node:Obj Self, Next:, Previous:Obj Declared Objects, Up:Obj Intro

Self, Message Sending, and Message Delegation

In SICStus Objects, each method is executed in the context of an object. This object may not be the static object where the method is declared. The current contextual object is used to determine dynamically which attributes are accessed, and which methods are called. This leads to a mechanism known as dynamic binding. This object can be retrieved using the universal method self(S), where S will be bound to the current contextual object.

When a message is sent to an object, the corresponding method will be executed in the context of the target object. A message delegated to an object will invoke a method that is executed in the context of the message-delegation operation.

object :: message
:: message

Message sending. Sends message to object, setting Self of the recipient to the recipient, i.e. object. If object is omitted, the recipient is the object in which the goal textually appears.

object <: message
<: message

Message delegation. Sends message to object, setting Self of the recipient to Self of the sender. If object is omitted, the recipient is the object in which the goal textually appears. Delegation preserves Self.

The following objects physical_object, a, and b are written using the default notations for sending and delegation, hiding the contextual variable Self:

physical_object :: {
        volume(50) &
        density(100) &
        weight(X) :-
                volume(V),
                density(D),
                :(X is V*D)
        }.

a :: {
        volume(5) &
        density(10) &

        Method :-
                physical_object <: Method
        }.

b :: {
        volume(5) &
        density(10) &

        Method :-
                physical_object :: Method
        }.

Notice that the difference between the objects a and b is that a delegates any message except volume(_) and density(_) to physical_object while b sends the message to physical_object. We may now ask

| ?- a :: weight(X), b :: weight(Y).

X = 50
Y = 5000

To get hold of the current contextual object, the universal method self(S) is provided. Another way to send a message to Self is to use the constant self. So the following two alternative definition of physical_object are equivalent to the previous one:

physical_object :: {
        volume(50) &
        density(100) &
        weight(X) :-
                self(S),
                S::volume(V),
                S::density(D),
                :(X is V*D)
        }.

physical_object :: {
        volume(50) &
        density(100) &
        weight(X) :-
                self::volume(V),
                self::density(D),
                :(X is V*D)
        }.


Node:Obj Hierarchies, Next:, Previous:Obj Self, Up:Obj Intro

Object Hierarchies, Inheritance, and Modules

The SICStus Objects system implements a default inheritance mechanism. By declaring within an object which objects are super-objects, the hierarchy of objects are maintained. The system also maintains for each object its immediate sub-objects (i.e. immediate children). Each object may also call Prolog predicates. At the top of the hierarchy, the proto-object object provides various services for other objects. If object is not used at the top of the hierarchy many services will not be available for other objects (check what methods are available in object by sending the message method/1 to object).


Node:Inheritance, Next:, Previous:Obj Hierarchies, Up:Obj Hierarchies

Inheritance

Immediate super-objects are declared by defining the method super/2 within the object. (Any definition super(Super) is transformed to super(Super,[])). The objects declared by super/2 are the immediate objects from which a method is inherited if not defined within the object. This implies that the inheritance mechanism is an overriding one. One could possibly have a union inheritance, whereby all clauses defining a method are collected from the super hierarchy and executed in a Prolog fashion. This can easily be programmed in SICStus Objects, using delegation to super objects.

The following example shows some objects used for animal classification.

animal :: {}.

bird :: {
        super(animal) &
        skin(feather) &
        habitat(tree) &
        motions(fly)
        }.

penguin :: {
        super(bird) &
        habitat(land) &
        motions(walk) &
        motions(swim) &
        size(medium)
        }.

| ?- penguin :: motions(M).
M = walk ;
M = swim ;
no

| ?- penguin :: skin(S).
S = feather ;
no

The following i