home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
rtsi.com
/
2014.01.www.rtsi.com.tar
/
www.rtsi.com
/
OS9
/
OSK
/
EFFO
/
pd3.lzh
/
SBPROLOG2.2
/
DOC
/
sbprolog_doc.readable
< prev
Wrap
Text File
|
1991-08-10
|
183KB
|
10,949 lines
The SB-Prolog System, Version 2.2
A User Manual
edited by
_S_a_u_m_y_a _K. _D_e_b_r_a_y
from material by
_D_a_v_i_d _S_c_o_t_t _W_a_r_r_e_n
_S_u_z_a_n_n_e _D_i_e_t_r_i_c_h
SUNY at Stony Brook
_F_e_r_n_a_n_d_o _P_e_r_e_i_r_a
SRI International
_M_a_r_c_h _1_9_8_7
Department of Computer Science
University of Arizona
Tucson, AZ 85721
The SB-Prolog System, Version 2.2
A User Manual
Abstract: SB-Prolog is a public-domain Prolog system for Unix|- based systems originally
developed at SUNY, Stony Brook. The core of the system is an emulator, written in C for
portability, of a Prolog virtual machine that is an extension of the Warren Abstract
Machine. The remainder of the system, including the translator from Prolog to the vir-
tual machine instructions, is written in Prolog. Parts of this manual, specifically the
sections on Prolog syntax and descriptions of some of the builtins, are based on the C-
Prolog User Manual by Fernando Pereira.
____________________
|- Unix is a trademark of AT&T.
_1. _I_n_t_r_o_d_u_c_t_i_o_n
SB-Prolog is a public domain Prolog system based on an extension of the Warren
Abstract Machine[1]. The WAM simulator is written in C to enhance portability. Prolog
source programs can be compiled into _b_y_t_e _c_o_d_e files, which contain encodings of WAM
instructions and are interpreted by the simulator. Programs can also be interpreted via
_c_o_n_s_u_l_t.
SB-Prolog offers several features that are not found on most Prolog systems
currently available. These include: compilation to object files; dynamic loading of
predicates; provision for generating executable code on the global stack, which can be
later be reclaimed; an _e_x_t_e_n_s_i_o_n _t_a_b_l_e facility that permits memoization of relations.
Other features include full integration between compiled and interpreted code, and a
____________________
[1] D. H. D. Warren, ``An Abstract Prolog Instruction Set'', Tech. Note 309, SRI
International, 1983.
2
facility for the definition and expansion of macros that is fully compatible with the
runtime system.
The following features are absent: we expect to incorporate them in future ver-
sions.
A ``listing'' feature, which produces a listing of clauses in the system database.
A garbage collector for the global stack.
The _r_e_c_o_r_d/_r_e_c_o_r_d_e_d/_e_r_a_s_e and the _c_u_r_r_e_n_t__a_t_o_m/_c_u_r_r_e_n_t__f_u_n_c_t_o_r/_c_u_r_r_e_n_t__p_r_e_d_i_c_a_t_e
facilities of C-Prolog.
In addition, it should be mentioned that while interpreted and compiled code behave
similarly in almost all cases, there are a few cases that we are aware of where they
behave differently:
3
(1) In cuts buried within _i_f-_t_h_e_n-_e_l_s_es (->): such cuts are treated as ``hard'' cuts in
interpreted code (i.e. cuts away alternative clauses as well), but as ``soft'' cuts
in compiled code (i.e. cuts as far back as the head of the clause, but does not cut
away alternative clauses).
(2) In the evaluation of arithmetic expressions involving compound subexpressions
created dynamically: in compiled code, this cannot be handled using is/2, and must
be handled using eval/2 (see the section on Arithmetic predicates), while in inter-
preted code either is/2 or eval/2 is acceptable.
4
_2. _G_e_t_t_i_n_g _S_t_a_r_t_e_d
This section is intended to give a broad overview of the SB-Prolog system, so as to
enable the new user to begin using the system with a minimum of delay. Many of the
topics touched on here are covered in greater depth in later sections.
_2._1. _T_h_e _D_y_n_a_m_i_c _L_o_a_d_e_r _S_e_a_r_c_h _P_a_t_h
In SB-Prolog, it is not necessary for the user to load all the predicates necessary
to execute a program. Instead, if an undefined predicate _f_o_o is encountered during exe-
cution, the system searches the user's directories in the order specified by the
environment variable SIMPATH until it finds a directory containing a file _f_o_o whose name
is that of the undefined predicate. It then dynamically loads and links the file _f_o_o
(which is expected to be a byte code file defining the predicate _f_o_o), and continues
with execution; if no such file can be found, an error message is given and execution
5
fails. This feature makes it unnecessary for the user to have to explicitly link in all
the predicates that might be necessary in a program: instead, only those files are
loaded which are necessary to have the program execute. This can significantly reduce
the memory requirements of programs.
The key to this dynamic search-and-load behaviour is the SIMPATH environment vari-
able, which specifies the order in which directories are to be searched. It may be set
by adding the following line to the user's ._c_s_h_r_c file:
setenv SIMPATH _p_a_t_h
where _p_a_t_h is a sequence of directory names separated by colons:
_d_i_r<1>:_d_i_r<2>: ... :_d_i_r<_n>
and _d_i_r<_i> are _f_u_l_l _p_a_t_h _n_a_m_e_s to the respective directories. For example, executing
6
the command
setenv SIMPATH .:$HOME/prolog/modlib:$HOME/prolog/lib
sets the search order for undefined predicates to the following: first, the directory in
which the program is executing is searched; if the appropriate file is not found in this
directory, the directories searched are, in order, ~/prolog/modlib and ~/prolog/lib. If
the appropriate file is not found in any of these directories, the system gives an error
message and execution fails.
The beginning user is advised to include the system directories (listed in the next
section) in his SIMPATH, in order to be able to access the system libraries (see below).
_2._2. _S_y_s_t_e_m _D_i_r_e_c_t_o_r_i_e_s
7
There are four basic system directories: cmplib, lib, modlib and sim. _c_m_p_l_i_b con-
tains the Prolog to byte code translator; _l_i_b and _m_o_d_l_i_b contain library routines. The
_s_r_c subdirectory in each of these contains the corresponding Prolog source programs.
The directory _s_i_m contains the simulator, the subdirectory _b_u_i_l_t_i_n contains code for the
builtin predicates of the system.
It is recommended that the beginning user include the system directories in his
SIMPATH, by setting SIMPATH to
.:_S_B_P/modlib:_S_B_P/lib:_S_B_P/cmplib
where _S_B_P denotes the path to the root of the SB-Prolog system directories.
_2._3. _I_n_v_o_k_i_n_g _t_h_e _S_i_m_u_l_a_t_o_r
The simulator is invoked by the command
sbprolog_b_c__f_i_l_e
8
where _b_c__f_i_l_e is a byte code file resulting from the compilation of a Prolog program.
In almost all cases, the user will wish to interact with the SB-Prolog _q_u_e_r_y _e_v_a_l_u_a_t_o_r,
in which case _b_c__f_i_l_e will be $_r_e_a_d_l_o_o_p, and the command will be
sbprolog /
_\ path \
//\$readloop
where /
_\_p_a_t_h\
/ is the path to the directory containing the command interpreter $_r_e_a_d_l_o_o_p.
This directory, typically, is _m_o_d_l_i_b (see Section 2.2 above).
The command interpreter reads in a query typed in by the user, evaluates it and
prints the answer(s), repeating this until it encounters an end-of-file (the standard
end-of-file character on the system, e.g. ctrl-D), or the user types in _e_n_d__o_f__f_i_l_e or
_h_a_l_t.
The user should ensure that the the directory containing the executable file _s_i_m
(typically, the system directory _s_i_m: see Section 2.2 above) is included in the shell
9
variable _p_a_t_h; if not, the full path to the simulator will have to be specified.
In general, the simulator may be invoked with a variety of options, as follows:
sbprolog-_o_p_t_i_o_n_s _b_c__f_i_l_e
or
sbprolog -_o_p_t_i_o_n<1> -_o_p_t_i_o_n<2> ... -_o_p_t_i_o_n<_n> _b_c__f_i_l_e
The options recognized by the simulator are described in Section 4.2.
When called with a byte code file _b_c__f_i_l_e, the simulator begins execution with the
first clause in that file. The first clause in such a file, therefore, should be a
clause without any arguments in the head (otherwise, the simulator will attempt to
dereference argument pointers in the head that are really pointing into deep space, and
usually come to a sad end). If the user is executing a file in this manner rather than
using the command interpreter, he should also be careful to include the undefined predi-
cate handler `_$_u_n_d_e_f_i_n_e_d__p_r_e_d'/1, which is normally defined in the file
_m_o_d_l_i_b/$_i_n_i_t__s_y_s._P.
10
_2._4. _E_x_e_c_u_t_i_n_g _P_r_o_g_r_a_m_s
There are two ways of executing a program: a source file may be compiled into a
byte-code file, which can then be loaded and executed; or, the source file may be inter-
preted via _c_o_n_s_u_l_t. The system supports full integration of compiled and interpreted
code, so that some predicates of a program may be compiled, while others may be inter-
preted. However, the unit of compilation or consulting remains the file. The remainder
of this section describes each of these procedures in more detail.
_2._4._1. _C_o_m_p_i_l_i_n_g _P_r_o_g_r_a_m_s
The compiler is invoked through the Prolog predicate _c_o_m_p_i_l_e. It translates Prolog
source programs into byte code that can then be executed on the simulator. The compiler
may be invoked as follows:
11
| ?- compile(_I_n_F_i_l_e [, _O_u_t_F_i_l_e ] [, _O_p_t_i_o_n_s_L_i_s_t ]).
or
| ?- compile(_I_n_F_i_l_e, _O_u_t_F_i_l_e, _O_p_t_i_o_n_s_L_i_s_t, _P_r_e_d_L_i_s_t).
where optional parameters are enclosed in brackets. _I_n_F_i_l_e is the name of the input
(i.e. source) file; _O_u_t_F_i_l_e is the name of the output file (i.e. byte code) file;
_O_p_t_i_o_n_s_L_i_s_t is a list of compiler options, and _P_r_e_d_L_i_s_t is a list of terms _P/_N denoting
the predicates defined in _I_n_F_i_l_e, where _P is a predicate name and _N its arity.
The input and output file names must be Prolog atoms, i.e. either begin with a
lower case letter and consist only of letters, digits, dollar signs and underscores; or,
be enclosed within single quotes. If the output file name is not specified, it defaults
to _I_n_F_i_l_e.out. The list of options, if specified, is a Prolog list, i.e. a term of the
form
[ _o_p_t_i_o_n<1>, _o_p_t_i_o_n<2>, ..., _o_p_t_i_o_n<_n> ].
12
If left unspecified, it defaults to the empty list []. _P_r_e_d_L_i_s_t, if specified, is usu-
ally given as an uninstantiated variable; its principal use is for setting trace points
on the predicates in the file (see Sections 6 and 8). Notice that _P_r_e_d_L_i_s_t can only
appear in _c_o_m_p_i_l_e/4.
A list of compiler options appears in Section 8.3.
_2._4._2. _L_o_a_d_i_n_g _B_y_t_e _C_o_d_e _F_i_l_e_s
Byte code files may be loaded into the simulator using the predicate _l_o_a_d:
| ?- load(_B_y_t_e_C_o_d_e__F_i_l_e).
where _B_y_t_e_C_o_d_e__F_i_l_e is a Prolog atom (see Section 3.1) that is the name of a byte code
file.
13
The _l_o_a_d predicate invokes the dynamic loader, which carries out a search according
to the sequence specified by the environment variable SIMPATH (see Section 2.1). It is
therefore not necessary to always specify the full path name to the file to be loaded.
Byte code files may be concatenated together to produce other byte code files.
Thus, for example, if _f_o_o_1 and _f_o_o_2 are byte code files resulting from the compilation
of two Prolog source programs, then the file _f_o_o, obtained by executing the shell com-
mand
cat foo1 foo2 > foo
is a byte code file as well, and may be loaded and executed. In this case, loading and
executing the file _f_o_o would give the same result as loading _f_o_o_1 and _f_o_o_2 separately,
which in turn would be the same as concatenating the original source files and compiling
this larger file. This makes it easier to compile large programs: one need only break
them into smaller pieces, compile the individual pieces, and concatenate the resulting
14
byte code files together.
_2._4._3. _C_o_n_s_u_l_t_i_n_g _P_r_o_g_r_a_m_s
Instead of compiling a file to generate a byte code file which then has to be
loaded, a program may be executed interpretively by ``consulting'' the corresponding
source file:
| ?- consult(_S_o_u_r_c_e_F_i_l_e [, _O_p_t_i_o_n_L_i_s_t ] ).
or
| ?- consult(_S_o_u_r_c_e_F_i_l_e, _O_p_t_i_o_n_L_i_s_t, _P_r_e_d_L_i_s_t).
where _S_o_u_r_c_e_F_i_l_e is a Prolog atom which is the name of a file containing a Prolog source
program; _O_p_t_i_o_n_L_i_s_t is a list of options to consult; and _P_r_e_d_L_i_s_t is a list of terms
_P/_N, where _P is a predicate name and _N its arity, specifying which predicates have been
consulted from _S_o_u_r_c_e_F_i_l_e; its principal use is for setting trace points on the predi-
cates in the file (see Section 6). Notice that _P_r_e_d_L_i_s_t can only appear in _c_o_n_s_u_l_t/3.
15
At this point, the options recognized for _c_o_n_s_u_l_t are the following:
first
If on, causes each clause read in to be added as the first clause of the database
(so that effectively, the clauses appear in the reverse order as in the source
file). Default: off.
index
If on, causes an index to be generated on the first argument of each predicate.
Default: off.
index(N)
If on, causes an index to be generated on the N[th] argument of each predicate.
Default: off.
16
q ``quick''. If on, invokes a consultation algorithm that is simpler and more effi-
cient than the general one. However, the code generated with the simpler algorithm
may not be correct if there are repeated variables within compound terms in the
body of the clause, e.g. in
p(X) :- q([X, X]).
Default: off.
t ``trace''. Causes a trace point to be set on any predicate in the current file
that does not already have a trace point set.
v ``verbose''. Causes information regarding which predicates have been consulted to
be printed out. Default: off.
In addition to the above, the options specified for the macro expander are also recog-
nized (see Section 10)).
17
It is important to note that SB-Prolog's _c_o_n_s_u_l_t predicate is similar to that of
Quintus Prolog, and behaves like C-Prolog's _r_e_c_o_n_s_u_l_t. This means that if a predicate
is defined across two or more files, consulting them will result in only the clauses in
the file consulted last being used.
_2._5. _E_x_e_c_u_t_i_o_n _D_i_r_e_c_t_i_v_e_s
Execution directives may be specified to _c_o_m_p_i_l_e and _c_o_n_s_u_l_t through :-/1. If, in
the read phase of _c_o_m_p_i_l_e or _c_o_n_s_u_l_t, a term with principal functor :-/1 is read in,
this term is executed directly via _c_a_l_l/1. This enables the user to dynamically modify
the environment, e.g. via _o_p declarations (see Section 3.2), _a_s_s_e_r_ts etc.
A point to note is that if the environment is modified as a result of an execution
directive, the modifications are visible only in that environment. This means that con-
sulted code, which runs in the environment in which the source program is read in (and
18
which is modified by such execution directives) feel the effects of such execution
directives. However, byte code resulting from compilation, which, in general, executes
in an environment different from that in which the source was compiled, does not inherit
the effects of such directives. Thus, an _o_p declaration can be used in a source file to
change the syntax and allow the remainder of the program to be parsed according to the
modified syntax; however, these modifications will not, in general, manifest themselves
if the byte code is executed in another environment. Of course, if the byte code is
loaded into the same environment as that in which the source program was compiled, e.g.
through
| ?- compile(foo, bar), load(bar).
the effects of execution directives will continue to be felt.
19
_3. _S_y_n_t_a_x
_3._1. _T_e_r_m_s
The syntax of SB-Prolog is by and large compatible with that of C-Prolog. The data
objects of the language are called _t_e_r_ms. A term is either a _c_o_n_s_t_a_n_t, a _v_a_r_i_a_b_l_e or
a _c_o_m_p_o_u_n_d _t_e_r_m. Constants can be _i_n_t_e_g_e_r_s or _a_t_o_m_s. The symbol for an atom must begin
with a lower case letter or the dollar sign $, and consist of any number of letters,
digits, underscores and dollar signs; if it contains any character other than these, it
must be enclosed within single quotes.[2] As in other programming languages, constants
are definite elementary objects.
____________________
[2] Users are advised against using symbols beginning with `$' or `_$', however, in
order to minimize the possibility of conflicts with symbols internal to the system.
20
Variables are distinguished by an initial capital letter or by the initial char-
acter "_", for example
X Value A A1 _3 _RESULT _result
If a variable is only referred to once, it does not need to be named and may be
written as an _a_n_o_n_y_m_o_u_s variable, indicated by the underline character "_".
A variable should be thought of as standing for some definite but unidentified
object. A variable is not simply a writeable storage location as in most pro-
gramming languages; rather it is a local name for some data object, cf. the variable
of pure LISP and constant declarations in Pascal.
The structured data objects of the language are the compound terms. A compound
term comprises a _f_u_n_c_t_o_r (called the _p_r_i_n_c_i_p_a_l functor of the term) and a sequence of
one or more terms called _a_r_g_u_m_e_n_t_s. A functor is characterised by its _n_a_m_e, which is an
atom, and its _a_r_i_t_y or number of arguments. For example the compound term whose functor
21
is named `point' of arity 3, with arguments X, Y and Z, is written
point(X,Y,Z)
An atom is considered to be a functor of arity 0.
A functor or predicate symbol is uniquely identified by its name and arity (in
other words, it is possible for different symbols having different arities to share the
same name). A functor or predicate symbol _p with arity _n is usually written _p/_n.
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 structure
22
s
/ \
np vp
| / \
john v np
| |
likes mary
Sometimes it is convenient to write certain functors as _o_p_e_r_a_t_o_r_s -- 2-ary functors
may be declared as _i_n_f_i_x operators and 1-ary functors as _p_r_e_f_i_x or _p_o_s_t_f_i_x operators.
Thus it is possible to write
X+Y (P;Q) X<Y +X P;
as optional alternatives to
+(X,Y) ;(P,Q) <(X,Y) +(X) ;(P)
Operators are described fully in the next section.
_L_i_s_ts 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 `.'/2 and two arguments which are
23
respectively the head and tail of the list. Thus a list of the first three
natural numbers is the structure
.
/ \
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
24
respectively.
Note that this list syntax is only syntactic sugar for terms of the form `.'(_,_)
and does not provide any new facilities that were not available otherwise.
For convenience, a further notational variant is allowed for lists of
integers which correspond to ASCII character codes. Lists written in this notation are
called _s_t_r_i_n_gs. For example,
"Prolog"
represents exactly the same list as
[80,114,111,108,111,103]
_3._2. _O_p_e_r_a_t_o_r_s
25
Operators in Prolog are simply a notational convenience. For example, the expres-
sion
2 + 1
could also be written +(2,1). It should be noticed that this expression represents the
structure
+
/ \
2 1
and not the number 3. The addition would only be performed if the structure was passed
as an argument to an appropriate procedure (such as eval/2 - see Section 5.2).
The Prolog syntax caters for operators of three main kinds - _i_n_f_i_x, _p_r_e_f_i_x and
_p_o_s_t_f_i_x. 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 argu-
ment.
26
Each operator has a _p_r_e_c_e_d_e_n_c_e, which is a number from 1 to 1200. The pre-
cedence is used to disambiguate expressions where the structure of the term
denoted is not made explicit through parenthesization. The general rule is that the
operator with the _h_i_g_h_e_s_t precedence is the principal functor. Thus if `+' has a
higher precedence than `/', then ``a+b/c'' and ``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, ``(a+b)/c''.
If there are two operators in the subexpression having the same highest pre-
cedence, the ambiguity must be resolved from the _t_y_p_e_s of the operators. The possible
types for an infix operator are
xfx xfy yfx
With an operator of type `xfx', it is a requirement that both of the two subexpres-
sions which are the arguments of the operator must be of _l_o_w_e_r precedence than the
27
operator itself, i.e. their principal functors must be of lower precedence,
unless the subexpression is explicitly bracketed (which gives it zero precedence).
With an operator of type `xfy', only the first or left-hand subexpression must be of
lower precedence; the second can be of the _s_a_m_e precedence as the main operator; and
vice versa for an operator of type `yfx'.
For example, if the operators `+' and `-' both have type `yfx' and are of the
same precedence, then the expression ``a-b+c'' is valid, and means ``(a-b)+c'', i.e.
``+(-(a,b),c)''. Note that the expression would be invalid if the operators had type
`xfx', and would mean ``a-(b+c)'', i.e. ``-(a,+(b,c))'', if the types were both `xfy'.
The possible types for a prefix operator are
fx fy
and for a postfix operator they are
28
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 preced-
ing expression would not be legal, although
not P
would still be a permissible form for "not(P)".
In SB-Prolog, a functor named _n_a_m_e is declared as an operator of type _t_y_p_e and
precedence _p_r_e_c_e_d_e_n_c_e by calling the evaluable predicate op:
| ?- op(_p_r_e_c_e_d_e_n_c_e,_t_y_p_e,_n_a_m_e).
The argument _n_a_m_e can also be a list of names of operators of the same type and pre-
29
cedence.
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. 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 _s_t_a_n_d_a_r_d in SB-Prolog, namely:
:- op( 1200, xfx, [ :-, --> ]).
:- op( 1200, fx, [ :-, ?- ]).
:- op( 1198, xfx, [ ::- ]).
:- op( 1100, xfy, [ ; ]).
:- op( 1050, xfy, [ -> ]).
:- op( 1000, xfy, [ ',' ]). /* See note below */
:- op( 900, fy, [ not, \+, spy, nospy ]).
:- op( 700, xfx, [ =, is, =.., ==, \==, <,>, =<,>=,
=:=, =\=, <, >, =<, >= ]).
:- op( 661, xfy, [ `.' ]).
:- op( 500, yfx, [ +, -, /\, \/ ]).
:- op( 500, fx, [ +, - ]).
:- op( 400, yfx, [ *, /, //, <<, >> ]).
:- op( 300, xfx, [ mod ]).
:- op( 200, xfy, [ ^ ]).
Operator declarations are most usefully placed in directives at the top of your
program files. In this case the directive should be a command as shown above. Another
common method of organisation is to have one file just containing commands to declare
30
all the necessary operators. This file is then always consulted first.
Note that a comma written literally as a punctuation character can be used as
though it were an infix operator of precedence 1000 and type `xfy':
X,Y ','(X,Y)
represent the same compound term. But note that a comma written as a quoted atom is
_n_o_t a standard operator.
Note also that the arguments of a compound term written in standard syntax
must be expressions of precedence _b_e_l_o_w 1000. Thus it is necessary to parenthesize the
expression "P :- Q" in
assert((P :- Q))
The following syntax restrictions serve to remove potential ambiguity associated with
prefix operators.
31
- In a term written in standard syntax, the principal functor and its following
"(" must _n_o_t be separated by any whitespace. Thus
point (X,Y,Z)
is invalid syntax (unless _p_o_i_n_t were declared as a prefix operator).
- If the argument of a prefix operator starts with a "(", this "(" must be
separated from the operator by at least one space or other non-printable charac-
ter. Thus
:-(p;q),r.
(where `:-' is the prefix operator) is invalid syntax, and must be written as
:- (p;q),r.
- If a prefix operator is written without an argument, as an ordinary atom,
the atom is treated as an expression of the same precedence as the prefix
32
operator, and must therefore be bracketed where necessary. Thus the brackets
are necessary in
X = (?-)
_4. _S_B-_P_r_o_l_o_g: _O_p_e_r_a_t_i_o_n_a_l _S_e_m_a_n_t_i_c_s
_4._1. _S_t_a_n_d_a_r_d _E_x_e_c_u_t_i_o_n _B_e_h_a_v_i_o_u_r
The normal execution behaviour of SB-Prolog follows the usual left to right order
of literals within a clause, and the textual top to bottom order of clauses for a predi-
cate. This corresponds to a depth first search of the leftmost SLD-tree for the program
and the given query. Unification without occurs check is used, and execution backtracks
to the most recent choice point when unification fails.
33
_4._2. _C_u_t_s _a_n_d _I_f-_T_h_e_n-_E_l_s_e
This standard execution behaviour of SB-Prolog can be changed using constructs like
_c_u_t (`!') and _i_f-_t_h_e_n-_e_l_s_e (`->'). In SB-Prolog, cuts are usually treated as _h_a_r_d, i.e.
discard choice points of all the literals to the left of the cut in the clause contain-
ing the cut being executed, and also the choice point for the parent predicate, i.e.
any remaining clauses for the predicate containing the cut being executed. There are
some situations, however, where the scope of a cut is restricted to be smaller than
this. Restrictions apply under the following conditions:
(1) The cut occurs in a term which has been constructed at runtime and called through
_c_a_l_l/1, e.g. in
..., X = (p(Y), !, q(Y)), ..., call(X), ...
In this case, the scope of the cut is restricted to be within the _c_a_l_l, unless one
34
of the following cases also apply and serve to restrict its scope further.
(2) The cut occurs in a negated goal, or within the scope of an if-then-else. In these
cases, the scope of the cut is restricted to be within the negation or the if-
then-else.
In cases involving nested occurrences of these situations, the scope of the cut is res-
tricted to that for the deepest such nested construct, i.e. most restricted. For exam-
ple, in the construct
..., not( (p(X) -> not( (q(X), (r(X) -> s(X) ; (t(X), !, u(X)))) )) ), ...
the scope of the cut is restricted to the inner if-then-else, and does not affect any
choice point that may have been set up for q(X).
The behaviour of the _i_f-_t_h_e_n-_e_l_s_e operator `->' is as follows: when executing the
goal
35
_P -> _Q ; _R
if _P succeeds, then any alternatives for _P are discarded and _Q is tried, while if _P
fails then _R is tried. Thus, -> may be thought of as
_P -> _Q ; _R :- _P, !, _Q.
_P -> _Q ; _R :- _R.
The scoping of cuts within if-then-elses is consistent with this conceptualization.
_4._3. _U_n_i_f_i_c_a_t_i_o_n _o_f _F_l_o_a_t_i_n_g _P_o_i_n_t _N_u_m_b_e_r_s
As far as unification is concerned, no type distinction is made between integers
and floating point numbers, and no explicit type conversion is necessary when unifying
an integer with a float. However, due to the finite precision representation of float-
ing point numbers and cumulative round-off errors in floating point arithmetic, com-
parisons involving floating point numbers may not always give the expected results. An
36
effort is made to minimize surprises by considering two numbers _x and _y (at least one of
which is a float) to be unifiable if ||_x| - |_y||/_m_i_n(|_x|, |_y|) to be less than 10[-5].
However, this does not guarantee immunity against round-off errors. For the same rea-
son, users are warned that indexing on predicate arguments (see Section 13) may not give
the expected results if floating point numbers are involved.
_5. _E_v_a_l_u_a_b_l_e _P_r_e_d_i_c_a_t_e_s
This section describes (most of) the evaluable predicates provided by SB-Prolog.
These can be divided into three classes: _i_n_l_i_n_e predicates, _b_u_i_l_t_i_n predicates and
_l_i_b_r_a_r_y predicates.
Inline predicates represent ``primitive'' operations in the WAM. Calls to inline
predicates are compiled into a sequence of WAM instructions in-line, i.e. without actu-
ally making a call to the predicate. Thus, for example, relational predicates (>/2,
37
>=/2, etc.) compile to, essentially, a subtraction and a conditional branch. Inline
predicates cannot be redefined by the user. Table 1 lists the SB-Prolog inline predi-
cates.
Unlike inline predicates, builtin predicates are implemented by C functions in the
simulator, and accessed via the inline predicate `_$_b_u_i_l_t_i_n'/1. Thus, if a builtin
predicate _f_o_o/3 was defined as builtin number 38, there would be a definition in the
system of the form
foo(X,Y,Z) :- '_$builtin'(38).
=/2 </2 =</2 >=/2
>/2 /\/2 `\/'/2 <</2
>>/2 =:=/2 =\=/2 is/2
/1 `_$savecp'/1 `_$cutto'/1 `_$builtin'/1
`_$call'/1 nonvar/1 var/1 fail/0
halt/0 true/0
Table 1: Inline Predicates of SB-Prolog
38
In effect, a builtin is simply a segment of code in a large case (i.e. _s_w_i_t_c_h)
statement. Each builtin is identified internally by an integer, referred to as its
``builtin number'', associated with it. The code for a builtin with builtin number _k
corresponds to the _k[_t_h.] case in the switch statement. SB-Prolog limits the total
number of builtins to 256.
Builtins, unlike inline predicates, can be redefined by the user. For example,
the predicate _f_o_o/3 above can be redefined simply by compiling the new definition into a
directory such that during dynamic loading, the new definition would be encountered
first and loaded.
A list of the builtins currently provided is listed in Appendix 1. Section 7.4
describes the procedure to be followed in order to define new builtin predicates.
Like builtin predicates, library predicates may also be redefined by the user. The
essential difference between builtin and library predicates is that whereas the former
39
are coded into the simulator in C, the latter are written in Prolog.
_5._1. _I_n_p_u_t _a_n_d _O_u_t_p_u_t
Input and output are done with respect to the current input and output streams.
These can be set, reset or checked using the file handling predicates described below.
The default input and output streams are denoted by user, and refer to the user's termi-
nal.
_5._1._1. _F_i_l_e _H_a_n_d_l_i_n_g
see(_F)
_F becomes the current input stream. _F must be instantiated to an atom at the time
of the call.
40
seeing(_F)
_F is unified with the name of the current input file.
seen Closes the current input stream.
tell(_F)
_F becomes the current output stream. _F must be instantiated to an atom at the time
of the call.
telling(_F)
_F is unified with the name of the current output file.
told
Closes the current output stream.
$exists(_F)
Succeeds if file _F exists.
41
_5._1._2. _T_e_r_m _I/_O
read(_X)
The next term, delimited by a full stop (i.e. a "." followed by a carriage-return
or a space), is read from the current input stream and unified with _X. The
syntax of the term must accord with current operator declarations. If a call
read(_X) causes the end of the current input stream to be reached, _X is unified
with the atom `end_of_file'. Further calls to read for the same stream will
then cause an error failure.
write(_X)
The term _X is written to the current output stream according to operator declara-
tions in force.
42
display(_X)
The term _X is displayed on the terminal in standard parenthesised prefix notation.
writeq(_T_e_r_m)
Similar to write(_T_e_r_m), but the names of atoms and functors are quoted where neces-
sary to make the result acceptable as input to read.
print(_T_e_r_m)
Prints out the term _T_e_r_m onto the user's terminal.
writename(_T_e_r_m)
If _T_e_r_m is an uninstantiated variable, its name, which looks a lot like an address
in memory, is written out; otherwise, the principal functor of _T_e_r_m is written out.
writeqname(_T_e_r_m)
As for writename, but the names are quoted where necessary.
43
_5._1._3. _C_h_a_r_a_c_t_e_r _I/_O
nl A new line is started on the current output stream.
get0(_N)
_N is the ASCII code of the next character from the current input stream. If the
current input stream reaches its end of file, a -1 is returned (however, unlike in
C-Prolog, the input stream is not closed on encountering end-of-file).
get(_N)
_N is the ASCII code of the next non-blank printable character from the current
input stream. It has the same behaviour as get0 on end of file.
put(_N)
ASCII character code _N is output to the current output stream. _N must be an
integer.
44
tab(_N)
_N spaces are output to the current output stream. _N must be an integer.
_5._2. _A_r_i_t_h_m_e_t_i_c
Arithmetic is performed by evaluable predicates which take as arguments
_a_r_i_t_h_m_e_t_i_c _e_x_p_r_e_s_s_i_o_n_s and _e_v_a_l_u_a_t_e them. An arithmetic expression is a term
built from _e_v_a_l_u_a_b_l_e _f_u_n_c_t_o_r_s, numbers and variables. At the time of evaluation,
each variable in an arithmetic expression must be bound to a number or to an arith-
metic expression. Each evaluable functor stands for an arithmetic operation.
The evaluable functors are as follows, where _X and _Y are arithmetic
expressions.
_X + _Y
addition.
45
_X - _Y
subtraction.
_X * _Y
multiplication.
_X / _Y
division.[3] Amounts to integer division if both _X and _Y are integers.
_X mod _Y
_X (integer) modulo _Y.
-_X unary minus.
_X /\ _Y
integer bitwise conjunction.
____________________
[3] The ``integer division'' operator `//' of C-Prolog is not supported; it can be
faked using _f_l_o_o_r/2 if necessary.
46
_X \/ _Y
integer bitwise disjunction.
_X << _Y
integer bitwise left shift of _X by _Y places.
_X >> _Y
integer bitwise right shift of _X by _Y places.
\_X integer bitwise negation.
As far as unification is concerned, no type distinction is made between integers
and floating point numbers, and no explicit type conversion is necessary when unifying
an integer with a float. However, due to the finite precision representation of float-
ing point numbers and cumulative round-off errors in floating point arithmetic, com-
parisons involving floating point numbers may not always give the expected results. An
47
effort is made to minimize surprises by considering two numbers _x and _y (at least one of
which is a float) to be unifiable if |_x - _y|/_m_i_n(|_x|, |_y|) to be less than 10[-5]. The
user should note, however, that this does not guarantee immunity against round-off
errors.
The arithmetic evaluable predicates are as follows, where _X and _Y stand for arith-
metic expressions, and _Z for some term. Note that this means that is only evaluates one
of its arguments as an arithmetic expression (the right-hand side one), whereas all the
comparison predicates evaluate both their arguments.
_Z is _X
Arithmetic expression _X is evaluated and the result, is unified with _Z. Fails if _X
is not an arithmetic expression. One point to note is that in compiled code, the
current implementation of is/2 cannot handle compound expressions created dynami-
cally: these have to be handled using eval/2. Thus, for example, the goals
48
..., X = Y + Z, Y = 3, Z = 2, W is X, ...
would fail, whereas
..., X = Y + Z, Y = 3, Z = 2, eval(X,W), ...
could succeed.
eval(_E, _X)
Evaluates the arithmetic expression _E and unifies the result with the term _X.
Fails if _E is not an arithmetic expression. The principal difference between
eval/2 and is/2 is that in compiled code, is/2 cannot handle arithmetic expressions
that are compound terms constructed at runtime, but eval/2 can. On the other hand,
is/2 is more efficient for the evaluation of static arithmetic expressions (i. e.
expressions that do not have compound subterms created at runtime). Another
difference is that while is/2 is an inline predicate, eval/2 is not; thus, is/2
cannot be redefined by the user, but eval/2 can.
49
_X =:= _Y
The values of _X and _Y are equal. If either _X or _Y involve compound subexpressions
that are created at runtime, they should first be evaluated using eval/2.
_X =\= _Y
The values of _X and _Y are not equal. If either _X or _Y involve compound subexpres-
sions that are created at runtime, they should first be evaluated using eval/2.
_X < _Y
The value of _X is less than the value of _Y. If either _X or _Y involve compound
subexpressions that are created at runtime, they should first be evaluated using
eval/2.
_X > _Y
50
The value of _X is greater than the value of _Y. If either _X or _Y involve compound
subexpressions that are created at runtime, they should first be evaluated using
eval/2.
_X =< _Y
The value of _X is less than or equal to the value of _Y. If either _X or _Y involve
compound subexpressions that are created at runtime, they should first be evaluated
using eval/2.
_X >= _Y
The value of _X is greater than or equal to the value of _Y. If either _X or _Y
involve compound subexpressions that are created at runtime, they should first be
evaluated using eval/2.
51
floor(_X, _Y)
If _X is a floating point number in the call and _Y is free, then _Y is instantiated
to the largest integer whose absolute value is not greater than the absolute value
of _X; if _X is uninstantiated in the call and _Y is an integer, then _X is instan-
tiated to the smallest float not less than _Y.
floatc(_F, _M, _E)
If _F is a number while _M and _E are uninstantiated in the call, then _M is instan-
tiated to a float _m (of magnitude less than 1), and _E to an integer _n, such that
_F = _m * 2[_n].
If _F is uninstantiated in the call while _M is a float and _E an integer, then _F
becomes instantiated to _M * 2[_E].
52
exp(_X, _Y)
If _X is instantiated to a number and _Y is uninstantiated in the call, then _Y is
instantiated to _e[_X] (where _e = 2.71828...); if _X is uninstantiated in the call
while _Y is instantiated to a positive number, then _X is instantiated to _l_o_g<_e>(_Y).
square(_X, _Y)
If _X is instantiated to a number while _Y is uninstantiated in the call, then _Y
becomes instantiated to _X[2]; if _X is uninstantiated in the call while _Y is instan-
tiated to a positive number, then _X becomes instantiated to the positive square
root of _Y (if _Y is negative in the call, _X becomes instantiated to 0.0).
sin(_X, _Y)
If _X is instantiated to a number (representing an angle in radians) and _Y is unin-
stantiated in the call, then _Y becomes instantiated to _s_i_n(_X) (the user should
53
check the magnitude of _X to make sure that the result is meaningful). If _Y is
instantiated to a number between -i~i~/2 and i~i~/2 and _X is uninstantiated in the
call, then _X becomes instantiated to _s_i_n[-1](_Y).
_5._3. _C_o_n_v_e_n_i_e_n_c_e
_P , _Q
_P and then _Q.
_P ; _Q
_P or _Q.
Always succeeds.
_X = _Y
Defined as if by the clause " Z=Z ", i.e. _X and _Y are unified.
54
_5._4. _E_x_t_r_a _C_o_n_t_r_o_l
! Cut (discard) all choice points made since the parent goal started execution. (The
scope of cut in different contexts is discussed in Section 4.2).
not _P
If the goal _P has a solution, fail, otherwise succeed. It is defined as if by
not(P) :- P, !, fail.
not(_).
_P -> _Q ; _R
Analogous to "if _P then _Q else _R" i.e. defined as if by
P -> Q ; R :- P, !, Q.
P -> Q ; R :- R.
_P -> _Q
When occurring other than as one of the alternatives of a disjunction, is
55
equivalent to
_P -> _Q ; fail.
repeat
Generates an infinite sequence of backtracking choices. It is defined by the
clauses:
repeat.
repeat :- repeat.
fail Always fails.
_5._5. _M_e_t_a-_L_o_g_i_c_a_l
var(_X)
Tests whether _X is currently instantiated to a variable.
56
nonvar(_X)
Tests whether _X is currently instantiated to a non-variable term.
atom(_X)
Checks that _X is currently instantiated to an atom (i.e. a non-variable
term of arity 0, other than a number).
integer(_X)
Checks that _X is currently instantiated to an integer.
real(_X)
Checks that _X is currently instantiated to a floating point number..
number(_X)
Checks that _X is currently instantiated to a number, i.e. that it is either an
integer or a real.
57
atomic(_X)
Checks that _X is currently instantiated to an atom or number.
structure(_X)
Checks that _X is currently instantiated to a compound term, i.e. to a nonvariable
term that is not atomic.
functor(_T,_F,_N)
The principal functor of term _T has name _F and arity _N, where _F is either an
atom or, provided _N is 0, a number. Initially, either _T must be instantiated to a
non-variable, or _F and _N must be instantiated to, respectively, either an
atom and a non-negative integer or an integer and 0. If these conditions are not
satisfied, an error message is given. In the case where _T is initially instan-
tiated to a variable, the result of the call is to instantiate _T to the most
general term having the principal functor indicated.
58
arg(_I,_T,_X)
Initially, _I must be instantiated to a positive integer and _T to a compound
term. The result of the call is to unify _X with the _Ith argument of term _T. (The
arguments are numbered from 1 upwards.) If the initial conditions are not satis-
fied or _I is out of range, the call merely fails.
_X =.. _Y
_Y is a list whose head is the atom corresponding to the principal functor of _X and
whose tail is the argument list of that functor in _X. E.g.
product(0,N,N-1) =.. [product,0,N,N-1]
N-1 =.. [-,N,1]
product =.. [product]
If _X is instantiated to a variable, then _Y 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.
59
name(_X,_L)
If _X is an atom or a number then _L is a list of the ASCII codes of the characters
comprising the name of _X. E.g.
name(product,[112,114,111,100,117,99,116])
i.e. name(product,"product").
If _X is instantiated to a variable, _L must be instantiated to a list of ASCII character
codes. E.g.
| ?- name(X,[104,101,108,108,111])).
X = hello
| ?- name(X,"hello").
X = hello
call(_X)
If _X is a nonvariable term in the program text, then it is executed exactly as if _X
appeared in the program text instead of _c_a_l_l(_X), e.g.
60
..., p(a), call( (q(X), r(Y)) ), s(X), ...
is equivalent to
..., p(a), q(X), r(Y), s(X), ...
However, if X is a variable in the program text, then if at runtime _X is instan-
tiated to a term which would be acceptable as the body of a clause, the goal
call(_X) is executed as if that term appeared textually in place of the call(_X),
_e_x_c_e_p_t _t_h_a_t any cut (`!') occurring in _X will remove only those choice points in
_X. If _X is not instantiated as described above, an error message is printed and
call fails.
_X (where _X is a variable) Exactly the same as call(_X). However, we prefer the expli-
cit usage of _c_a_l_l/1 as good programming practice, and the use of a top level vari-
able subgoal elicits a warning from the compiler.
61
conlength(_C,_L)
Succeeds if the length of the print name of the constant _C (which can be an atom,
buffer or integer), in bytes, is _L. If _C is a buffer (see Section 5.8), it is the
length of the buffer; if _C is an integer, it is the length of the decimal represen-
tation of that integer, i.e., the number of bytes that a $_w_r_i_t_e_n_a_m_e will use.
_5._6. _S_e_t_s
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 back-
tracking and gradually building up a list of the solutions. The following evaluable
predicates are provided to automate this process.
setof(_X,_P,_S)
Read this as "_S is the set of all instances of _X such that _P is provable''. If
62
_P is not provable, setof(_X,_P,_S) succeeds with _S instantiated to the empty list [].
The term _P specifies a goal or goals as in call(_P). _S is a set of terms represented
as a list of those terms, without duplicates, in the standard order for terms
(see Section 5.7). If there are uninstantiated variables in _P which do not also
appear in _X, then a call to this evaluable predicate may backtrack, generat-
ing alternative values for _S corresponding to different instantiations of the
free variables of _P. Variables occurring in _P will not be treated as free if they
are explicitly bound within _P by an existential quantifier. An existential quan-
tification is written:
_Y^_Q
meaning "there exists a _Y such that _Q is true", where _Y is some Prolog term (usu-
ally, a variable, or tuple or list of variables).
63
bagof(_X,_P,_B_a_g)
This is the same as setof except that the list (or alternative lists) returned will
not be ordered, and may contain duplicates. If _P is unsatisfiable, _b_a_g_o_f
succeeds binding _B_a_g to the empty list. The effect of this relaxation is to save
considerable time and space in execution.
findall(_X,_P,_L)
Similar to _b_a_g_o_f/3, except that variables in _P that do not occur in _X are treated
as local, and alternative lists are not returned for different bindings of such
variables. The list _L is, in general, unordered, and may contain duplicates. If _P
is unsatisfiable, _f_i_n_d_a_l_l succeeds binding _S to the empty list.
_X^_P
The system recognises this as meaning "there exists an _X such that _P is true",
and treats it as equivalent to call(_P). The use of this explicit existential
64
quantifier outside the setof and bagof constructs is superfluous.
_5._7. _C_o_m_p_a_r_i_s_o_n _o_f _T_e_r_m_s
These evaluable predicates are meta-logical. They treat uninstantiated
variables as objects with values which may be compared, and they never instan-
tiate those variables. They should _n_o_t be used when what you really want is arithmetic
comparison (Section 5.2) or unification.
The predicates make reference to a standard total ordering of terms, which is as
follows:
variables, in a standard order (roughly, oldest first - the order is _n_o_t related
to the names of variables);
numbers, from -"infinity" to +"infinity";
65
atoms, in alphabetical (i.e. ASCII) order;
complex terms, ordered first by arity, then by the name of principal functor, then
by the arguments (in left-to-right order).
For example, here is a list of terms in the standard order:
[ X, -9, 1, fie, foe, fum, X = Y, fie(0,2), fie(1,1) ]
These are the basic predicates for comparison of arbitrary terms:
_X == _Y
Tests if the terms currently instantiating _X and _Y are literally identical (in
particular, variables in equivalent positions in the two terms must be identical).
For example, the question
| ?- X == Y.
fails (answers "no") because _X and _Y are distinct uninstantiated variables.
66
However, the question
| ?- X = Y, X == Y.
succeeds because the first goal unifies the two variables (see page 42).
_X \== _Y
Tests if the terms currently instantiating _X and _Y are not literally
identical.
_T_1 @< _T_2
Term _T_1 is before term _T_2 in the standard order.
_T_1 @> _T_2
Term _T_1 is after term _T_2 in the standard order.
67
_T_1 @=< _T_2
Term _T_1 is not after term _T_2 in the standard order.
_T_1 @>= _T_2
Term _T_1 is not before term _T_2 in the standard order.
Some further predicates involving comparison of terms are:
compare(_O_p,_T_1,_T_2)
The result of comparing terms _T_1 and _T_2 is _O_p, where the possible values for _O_p
are:
`=' if _T_1 is identical to _T_2,
`<' if _T_1 is before _T_2 in the standard order,
`>' if _T_1 is after _T_2 in the standard order.
Thus compare(=,_T_1,_T_2) is equivalent to _T_1 == _T_2.
68
sort(_L_1,_L_2)
The elements of the list _L_1 are sorted into the standard order, and any identical
(i.e. `==') elements are merged, yielding the list _L_2.
_5._8. _B_u_f_f_e_r_s
SB-Prolog supports the concept of buffers. A buffer is actually a constant and the
characters that make up the buffer is the name of the constant. However, the symbol
table entry for a buffer is not hashed and thus is not added to the obj-list, so two
different buffers will never unify. Buffers can be allocated either in permanent space
or on the heap. Buffers in permanent space stay there forever; buffers on the heap are
deallocated when the ``allocate buffer'' goal is backtracked over.
A buffer allocated on the heap can either be a simple buffer, or it can be allo-
cated as a subbuffer of another buffer already on the heap. A subbuffer will be
69
deallocated when its superbuffer is deallocated.
There are occasions when it is not known, in advance, exactly how much space will
be required and so how big a buffer should be allocated. Sometimes this problem can be
overcome by allocating a large buffer and then, after using as much as is needed,
returning the rest of the buffer to the system. This can be done, but only under _v_e_r_y
limited circumstances: a buffer is allocated from the end of the permanent space, the
top of the heap, or from the next available space in the superbuffer; if no more space
has been used beyond the end of the buffer, a tail portion of the buffer can be returned
to the system. This operation is called ``trimming'' the buffer.
The following is a list of library predicates for buffer management (predicates
whose names begin with `$' are low-level routines intended only for serious hackers wil-
ling to put up with little or no protection):
70
alloc_perm(_S_i_z_e, _B_u_f_f)
Allocates a buffer with a length _S_i_z_e in the permanent (i.e. program) area. _S_i_z_e
must be bound to a number. On successful return, _B_u_f_f will be bound to the allo-
cated buffer. The buffer, being in the permanent area, is never de-allocated.
alloc_heap(_S_i_z_e, _B_u_f_f)
Allocates a buffer of size _S_i_z_e on the heap and binds _B_u_f_f to it. Since it is on
the heap, it will be deallocated on backtracking.
$alloc_buff(_S_i_z_e,_B_u_f_f,_T_y_p_e,_S_u_p_b_u_f_f,_R_e_t_c_o_d_e)
Allocates a buffer. _S_i_z_e is the length (in bytes) of the buffer to allocate; _B_u_f_f
is the buffer allocated, and should be unbound at the time of the call; _T_y_p_e indi-
cates where to allocate the buffer: a value of 0 indicates that the buffer is to be
allocated in permanent space, 1 that it should be on the heap, and 2 indicates that
it should be allocated from a larger heap buffer; _S_u_p_b_u_f_f is the larger buffer to
71
allocate a subbuffer out of, and is only looked at if the value of _T_y_p_e is 2;
_R_e_t_c_o_d_e is the return code: a value of 0 indicates that the buffer has been allo-
cated, while a value of 1 indicates that the buffer could not be allocated due to
lack of space. The arguments _S_i_z_e, _T_y_p_e, and _S_u_p_b_u_f_f (if _T_y_p_e = 2) are input argu-
ments, and should be bound at the time of the call; _B_u_f_f and _R_e_t_c_o_d_e are output
arguments, and should be unbound at the time of the call.
trimbuff(_T_y_p_e, _B_u_f_f, _N_e_w_l_e_n)
This allows (in some very restricted circumstances) the changing of the size of a
buffer. _T_y_p_e is 0 if the buffer is permanent, 1 if the buffer is on the heap. _B_u_f_f
is the buffer. _N_e_w_l_e_n is an integer: the size (which should be smaller than the
original length of the buffer) to make the buffer. If the buffer is at the top of
the heap (if heap buffer) or the end of the program area (if permanent) then the
heap-top (or program area top) will be readjusted down. The length of the buffer
72
will be modified to _N_e_w_l_e_n. This is (obviously) a very low-level primitive and is
for hackers only to implement grungy stuff.
$trim_buff(_S_i_z_e,_B_u_f_f,_T_y_p_e,_S_u_p_b_u_f_f)
Trims the buffer _B_u_f_f (possibly contained in superbuffer _S_u_p_b_u_f_f) of type _T_y_p_e to
_S_i_z_e bytes. The value of _T_y_p_e indicates where the buffer is located: a value of 0
denotes a buffer in permanent space, a value of 1 a buffer on the heap, and a value
of 2 a buffer within another buffer (the superbuffer). All the arguments are input
arguments, and should be instantiated at the time of call (with the possible excep-
tion of _S_u_p_b_u_f_f, which is looked at only if _T_y_p_e is 2). The internal length of the
buffer _B_u_f_f is changed to _S_i_z_e.
conlength(_C_o_n_s_t_a_n_t,_L_e_n_g_t_h)
73
Succeeds if the length of the print name of the constant _C_o_n_s_t_a_n_t (which can be an
atom, buffer or integer), in bytes, is _L_e_n_g_t_h. If _C_o_n_s_t_a_n_t is a buffer, it is the
length of the buffer; if _C_o_n_s_t_a_n_t is an integer, it is the length of the decimal
representation of that integer, i.e., the number of bytes that a $_w_r_i_t_e_n_a_m_e will
use.
_5._9. _M_o_d_i_f_i_c_a_t_i_o_n _o_f _t_h_e _P_r_o_g_r_a_m
The predicates defined in this section allow modification of the program as it is
actually running. Clauses can be added to the program (_a_s_s_e_r_t_e_d) or removed from the
program (_r_e_t_r_a_c_t_e_d). At the lowest level, the system supports the asserting of clauses
with upto one literal in the body. It does this by allocating a buffer and compiling
code for the clause into that buffer. Such a buffer is called a ``clause reference''
(_c_l_r_e_f). The clref is then added to a chain of clrefs. The chain of clrefs has a
74
header, which is a small buffer called a ``predicate reference'' (_p_r_r_e_f), which contains
pointers to the beginning and end of its chain of clrefs. Clause references are quite
similar to ``database references'' of C-Prolog, and can be called.
A prref is normally associated with a predicate symbol and contains the clauses
that have been asserted for that symbol. However, prrefs can be constructed and clrefs
added to them, and such clauses can be called, all without associating that prref with
any particular predicate symbol. A predicate symbol that has an associated prref is
called a ``dynamic'' predicate (other predicate types are ``compiled'' and ``unde-
fined'').
There are options as to where clrefs are allocated and how they are linked to a
chain of clrefs associated with a prref. A clref can either be allocated in per-
manent space (the normal arrangement) or as a sub-buffer of a superbuffer on the heap.
When adding a clref to a prref chain, it can be be added at the beginning of the
75
chain or at the end of the chain. In addition, one of the argument positions can be
used to index, so that subsequent retrievals will try to index on that position.
assert(_C)
The current instance of _C is interpreted as a clause and is added to the program
(with new private variables replacing any uninstantiated variables), at the end of
the list of clauses for that predicate. _C must be instantiated to a non-variable.
assert(_C, _O_p_t_s)
As for _a_s_s_e_r_t/1, with _O_p_t_s a list of options. The options currently recognized
are:
first
76
If on, causes the asserted clause to be added as the first clause of the database.
Default: off.
index
If on, causes an index to be generated on the first argument of the clause.
Default: off.
index(N)
If on, causes an index to be generated on the N[th] argument of the clause.
Default: off.
q
``quick''. If on, invokes an assertion algorithm that is simpler and more effi-
cient than the general one. However, the code generated with the simpler algorithm
may not be correct if there are repeated variables within compound terms in the
77
body of the clause, e.g. in
p(X) :- q([X, X]).
Default: off.
asserti(_C,_N)
The current instance of _C, interpreted as a clause, is asserted to the program with
an index on its _N[_t_h] argument. If _N is zero, no index is created.
asserta(_C)
Similar to assert(_C), except that the new clause becomes the _f_i_r_s_t clause of the
procedure concerned.
asserta(_C, _R_e_f)
Similar to asserta(_C), but also unifies _R_e_f with the clause reference of the clause
asserted.
78
assertz(_C)
Similar to assert(_C), except that the new clause becomes the _l_a_s_t clause of the
procedure concerned.
assertz(_C, _R_e_f)
Similar to assertz(_C), but also unifies _R_e_f with the clause reference of the clause
asserted.
assert_union(_P, _Q)
The clauses for _Q are added to the clauses for _P. For example, the call
| ?- assert_union(p(X,Y),q(X,Y)).
has the effect of adding the rule
p(X,Y) :- q(X,Y).
as the last rule defining _p/2. If _P is not defined, it results in the call to _Q
79
being the only clause for _P.
The variables in the arguments to _a_s_s_e_r_t__u_n_i_o_n/2 are not significant, e.g. the
above would have been equivalent to
| ?- assert_union(p(Y,X),q(X,Y)).
or
| ?- assert_union(p(_,_),q(_,_)).
However, the arities of the two predicates involved must match, e.g. even though
the goal
| ?- assert_union(p(X,Y), r(X,Y,Z)).
will succeed, the predicate _p/2 will not in any way depend on the clauses for _r/3.
assert(_C_l_a_u_s_e,_A_Z,_I_n_d_e_x,_C_l_r_e_f)
Asserts a clause to a predicate. _C_l_a_u_s_e is the clause to assert. _A_Z is 0 for
insertion as the first clause, 1 for insertion as the last clause. _I_n_d_e_x is the
80
number of the argument on which to index (0 for no indexing). _C_l_r_e_f is returned
as the clause reference of the fact newly asserted. If the main functor symbol of
_C_l_a_u_s_e has been declared (by $_a_s_s_e_r_t_f__a_l_l_o_c__t/2, see below) to have its clauses on
the heap, the clref will be allocated there. If the predicate symbol of _C_l_a_u_s_e is
undefined, it will be initialized and _C_l_a_u_s_e added. If the predicate symbol has
compiled clauses, it is first converted to be dynamic (see _s_y_m_t_y_p_e/2, Section 5.10)
by adding a special clref that calls the compiled clauses. _F_a_c_t, _A_Z and _I_n_d_e_x are
input arguments, and should be instantiated at the time of call; _C_l_r_e_f is an output
argument, and should be uninstantiated at the time of call.
retract(_H_e_a_d)
The first clause in the program whose head matches _H_e_a_d is erased. This predicate
may be used in a non-deterministic fashion, i.e. it will successively backtrack to
retract clauses whose heads match _H_e_a_d. _H_e_a_d must be initially instantiated to a
81
non-variable.
abolish(_P)
Completely remove all clauses for the procedure with head _P (which should be a
term). For example, the goal
| ?- abolish( p(_, _, _) ).
removes all clauses for the predicate _p/3.
abolish(_P, _N)
Completely remove all clauses for the predicate _P (which should be an atom) with
arity _N (which should be an integer).
call_ref(_C_a_l_l, _R_e_f)
Calls the predicate whose database reference (prref) is _R_e_f, using the literal _C_a_l_l
as the call. This is similar to call_ref(_C_a_l_l, _R_e_f, 0).
82
call_ref(_C_a_l_l, _R_e_f, _T_r)
Calls the predicate whose database reference (prref) is _R_e_f, using the literal _C_a_l_l
as the call. _T_r must be either 0 or 1: if _T_r is 0 then the call _C_a_l_l is made
assuming the ``trust'' optimization will be made; if _T_r is 1 then the ``trust''
optimization is not used, so that any new fact added before final failure will be
seen by _C_a_l_l. (Also, this currently does not take advantage of any indexing that
might have been constructed, while $_d_b__c_a_l_l__p_r_r_e_f does.) _C_a_l_l, _R_e_f and _T_r are all
input arguments, and should be instantiated at the time of call.
The basic library predicates that support the manipulation of prrefs and clrefs are as
follows:
$db_new_prref(_P_r_r_e_f,_W_h_e_r_e,_S_u_p_b_u_f_f)
83
Creates an empty Prref, i.e. one with no facts in it. If called, it will simply
fail. _W_h_e_r_e indicates where the prref should be allocated: a value of 0 indicates
the permanent area, while a value of 2 indicates that it is to be allocated as a
subbuffer. _S_u_p_b_u_f_f is the superbuffer from which to allocate _P_r_r_e_f if _W_h_e_r_e is 2.
_W_h_e_r_e should be instantiated at the time of call, while _P_r_r_e_f should be uninstan-
tiated; in addition, if _W_h_e_r_e is 2, _S_u_p_b_u_f_f should be instantiated at the time of
call.
$db_assert_fact(_F_a_c_t,_P_r_r_e_f,_A_Z,_I_n_d_e_x,_C_l_r_e_f,_W_h_e_r_e,_S_u_p_b_u_f_f)
_F_a_c_t is a fact to be asserted; _P_r_r_e_f is a predicate reference to which to add the
asserted fact; _A_Z is either 0, indicating the fact should be inserted as the first
clause in _P_r_r_e_f, or 1, indicating it should be inserted as the last; _I_n_d_e_x is 0 if
no index is to be built, or _n if an index on the _n[th] argument of the fact is to
be used. (Asserting at the beginning of the chain with indexing is not yet
84
supported.) _W_h_e_r_e indicates where the clref is to be allocated: a value of 0 indi-
cates that it should be in the permanent area, while a value of 2 indicates that it
should be allocated as a subbuffer of _S_u_p_b_u_f_f. _C_l_r_e_f is returned and it is the
clause reference of the asserted fact. _F_a_c_t, _P_r_r_e_f, _A_Z, _I_n_d_e_x and _W_h_e_r_e are
input arguments, and should be instantiated at the time of call; in addition, if
_W_h_e_r_e is 2, then _S_u_p_b_u_f_f should also be instantiated. _C_l_r_e_f is an output argument,
and should be uninstantiated at the time of call.
$db_add_clref(_F_a_c_t,_P_r_r_e_f,_A_Z,_I_n_d_e_x,_C_l_r_e_f,_W_h_e_r_e,_S_u_p_b_u_f_f)
Adds the clref _C_l_r_e_f to the prref _P_r_r_e_f. _F_a_c_t is the fact that has been compiled
into _C_l_r_e_f (used only to get the arity and for indexing). The other parameters are
as for $_d_b__a_s_s_e_r_t__f_a_c_t/7.
$db_call_prref(_C_a_l_l,_P_r_r_e_f)
85
Calls the prref _P_r_r_e_f using the literal _C_a_l_l as the call. The call is done by sim-
ply branching to the first clause. New facts added to _P_r_r_e_f after the last fact
has been retrieved by _C_a_l_l, but before _C_a_l_l is failed through, will _n_o_t be used.
Both _C_a_l_l and _P_r_r_e_f are input arguments, and should be instantiated at the time of
call.
$db_call_prref_s(_C_a_l_l,_P_r_r_e_f)
This also calls the prref _P_r_r_e_f using _C_a_l_l as the call. The difference from
$_d_b__c_a_l_l__p_r_r_e_f is that this does not use the ``trust'' optimization, so that any
new fact added before final failure will be seen by _C_a_l_l. (Also, this currently
does not take advantage of any indexing that might have been constructed, while
$_d_b__c_a_l_l__p_r_r_e_f does.) Both _C_a_l_l and _P_r_r_e_f are input arguments, and should be
instantiated at the time of call.
86
$db_get_clauses(_P_r_r_e_f,_C_l_r_e_f,_D_i_r)
This returns, nondeterministically, all the clause references _C_l_r_e_f for clauses
asserted to prref _P_r_r_e_f. If _D_i_r is 0, then the first clref on the list is returned
first; if _D_i_r is 1, then they are returned in reverse order. _P_r_r_e_f and _D_i_r are
input arguments, and should be instantiated at the time of call; _C_l_r_e_f is an output
argument, and should be uninstantiated at the time of call.
$db_kill_clause(_C_l_r_e_f)
This predicate retracts the fact referenced by clref _C_l_r_e_f. It does this by simply
making the first instruction of the clause a _f_a_i_l instruction. This means that
this clause will fail whenever it is called in the future, no matter how it is
accessed. _C_l_r_e_f should be instantiated at the time of call.
87
_5._1_0. _E_n_v_i_r_o_n_m_e_n_t_a_l
op(_p_r_i_o_r_i_t_y, _t_y_p_e, _n_a_m_e)
Treat _n_a_m_e as an operator of the stated _t_y_p_e and _p_r_i_o_r_i_t_y (see Section 3.2). _n_a_m_e
may also be a list of names, in which all are to be treated as operators of the
stated _t_y_p_e and _p_r_i_o_r_i_t_y.
break
Causes the current execution to be suspended at the next procedure call. Then the
message ``[ Break (level 1) ]'' is displayed. The interpreter is then ready to
accept input as though it was at the top level (except that at break level _n > 0,
the prompt is ``_n: ?- ''). If another call of break is encountered, it moves up to
level 2, and so on. To close the break and resume the execution which was
suspended, type the END-OF-INPUT character. Execution will be resumed at the
88
procedure call where it had been suspended. Alternatively, the suspended execution
can be aborted by calling the evaluable predicate abort, which causes a return to
the top level.
abort
Aborts the current execution, taking you back to top level.
save(_F)
The system saves the current state of the system into file _F.
restore(_F)
The system restores the saved state in file _F to be the current state. One res-
triction imposed by the current system is that various system parameters (e.g.
stack sizes, permanent space, heap space, etc.) of the saved state have to be the
same as that of the current invocation. Thus, it is not possible to save a state
89
from an invocation where 50000 words of permanent space had been allocated, and
then restore the same state in an invocation with 100000 words of permanent space.
cputime(_X)
Unifies _X with the time elapsed, in milliseconds, since the system was started up.
$getenv(_V_a_r,_V_a_l)
_V_a_l is unified with the value of the Unix environment variable _V_a_r.
statistics
Prints out the current allocations and amounts of space used for each of the four
main areas: the permanent area, the local stack, the global stack and the trail
stack. Does not work well unless the simulator has been called with the -s option
(see Section 7.2).
90
symtype(_T,_N)
Unifies _N with the ``internal type'' of the principal functor of the term _T, which
must be instantiated at the time of the call. _N is bound to 0 if _T does not have
an entry point defined (i.e. cannot be executed); to 1 if the principal functor of
_T is ``dynamic'', i.e. has asserted code; to 2 if the principal functor for _T is a
compiled predicate; and 3 if _T denotes a buffer. Thus, for example, if the predi-
cate _p/2 is a compiled predicate which has been loaded into the system, the goal
| ?- symtype(p(_,_), X).
will succeed binding X to 2; on the other hand, the goal
| ?- assert(q(a,b,c)), symtype(q(_,_,_), X).
will succeed binding X to 1.
91
system(_C_a_l_l)
Calls the operating system with the atom _C_a_l_l as argument. For example, the call
| ?- system('ls').
will produce a directory listing. Since _s_y_s_t_e_m/1 is executed by forking off a
shell process, it cannot be used, for example, to change the working directory of
the simulator.
syscall(_N,_A_r_g_s,_R_e_s)
Executes the Unix system call number _N with arguments _A_r_g_s, and returns the result
in _R_e_s. _N is an integer, and _A_r_g_s a Prolog list of the arguments to the system
call. For example, to execute the system call ``_c_r_e_a_t(_F_i_l_e,_M_o_d_e)'', knowing that
the syscall number for the Unix command _c_r_e_a_t(2) is 8, we execute the goal
| ?- syscall(8, [_F_i_l_e, _M_o_d_e], _D_e_s).
92
where _D_e_s is the file descriptor returned by _c_r_e_a_t. The syscall numbers for some
Unix system calls are given in Table 2.
_5._1_1. _G_l_o_b_a_l _V_a_l_u_e_s
SB-Prolog has some primitives that permit the programmer to manipulate global
values. These are provided primarily as an efficiency hack, and needless to say, should
be used with a great deal of care.
________________________________________________________________________________________
exit 1 fork 2
read 3 write 4
open 5 close 6
creat 8 link 9
unlink 10 chdir 12
chmod 15 lseek 19
access 33 kill 37
wait 84 socket 97
connect 98 accept 99
send 101 recv 102
bind 104 setsockopt 105
listen 106 recvmsg 113
sendmsg 114 getsockopt 118
recvfrom 125 sendto 133
socketpair 135 mkdir 136
rmdir 137 getsockname 150
________________________________________________________________________________________
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Table 2: Some Syscall Numbers for Unix Systems Calls
93
globalset(_T_e_r_m)
Allows the user to save a global value. _T_e_r_m must be bound to a compound term, say
_p(_V). _V must be a number or a constant or a variable. If _V is a number or a con-
stant, the effect of _g_l_o_b_a_l_s_e_t(_p(_V)) can be described as:
retract(p(_)), assert(p(V)).
I.e., _p is a predicate that when called will, from now on (until some other change
by _g_l_o_b_a_l_s_e_t/1), deterministically return _V. If _V is a variable, the effect is to
make _V a global variable whose value is accessible by calling _p. For example, exe-
cuting ``_g_l_o_b_a_l_s_e_t(_p(_X))'' makes _X a global variable. _X can be set by unification
with some other term. On backtracking, _X will be restored to its earlier value.
gennum(_N_e_w_n_u_m)
94
gennum/1 sets its argument to a new integer every time it is invoked.
gensym(_C,_N_e_w_s_y_m)
gensym/2 sets its second argument to an atom whose name is made by concatenating
the name of the atom _C to the current gennum number. This new constant is bound to
_N_e_w_s_y_m. For example, if the current _g_e_n_n_u_m number is 37, then the call
| ?- gensym(aaa,X)
will succeed binding _X to the atom `aaa37'.
_6. _D_e_b_u_g_g_i_n_g
_6._1. _H_i_g_h _L_e_v_e_l _T_r_a_c_i_n_g
The preferred method of tracing execution is through the predicate _t_r_a_c_e/1. This
predicate takes as argument a term _P/_N, where _P is a predicate name and _N its arity, and
95
sets a ``trace point'' on the corresponding predicate; it can also be given a list of
such terms, in which case a trace point is set on each member of the list. For example,
executing
| ?- trace(pred1/2), trace([pred2/3, pred3/2]).
sets trace points on predicates _p_r_e_d_1/2, _p_r_e_d_2/3 and _p_r_e_d_3/2. Only those predicates are
traced that have trace points set on them.
If all the predicates in a file are to be traced, it is usually convenient to use
the _P_r_e_d_L_i_s_t parameter of _c_o_m_p_i_l_e/4 or _c_o_n_s_u_l_t/3, e.g.:
| ?- compile(foo, 'foo.out', [t,v], Preds), load('foo.out'), trace(Preds).
or
| ?- consult(foo, [v], Preds), trace(Preds).
Notice that in the first case, the t compiler option (see Section 8.3) should be speci-
fied in order to turn off certain assembler optimizations and facilitate tracing. In
the second case, the same effect may be achieved by specifying the t option to _c_o_n_s_u_l_t.
96
The trace points set on predicates may be overwritten by loading byte code files
via _l_o_a_d/1, and in this case it may be necessary to explicitly set trace points again on
the loaded predicates. This does not happen with _c_o_n_s_u_l_t: predicates that were being
traced continue to have trace points set after consulting.
The tracing facilities of SB-Prolog are in many ways very similar to those of C-
Prolog. However, leashing is not supported, and only those predicates can be traced
which have had trace points set on them through _t_r_a_c_e/1. This makes _t_r_a_c_e/1 and _s_p_y/1
very similar: essentially, trace amounts to two levels of spy points. In SB-Prolog,
tracing occurs at _C_a_l_l (i.e. entry to a predicate), successful _E_x_i_t from a clause, and
_F_a_i_l_u_r_e of the entire call. The tracing options available during debugging are the fol-
lowing:
c, NEWLINE: Creep
Causes the system to single-step to the next port (i.e. either the entry to a
97
traced predicate called by the executed clause, or the success or failure exit from
that clause).
a: Abort
Causes execution to abort and control to return to the top level interpreter.
b: Break
Calls the evaluable predicate _b_r_e_a_k, thus invoking recursively a new incarnation of
the system interpreter. The command prompt at break level _n is
_n: ?-
The user may return to the previous break level by entering the system end-of-file
character (e.g. ctrl-D), or typing in the atom _e_n_d__o_f__f_i_l_e; or to the top level
interpreter by typing in _a_b_o_r_t.
98
f: Fail
Causes execution to fail, thus transferring control to the Fail port of the current
execution.
h: Help
Displays the table of debugging options.
l: Leap
Causes the system to resume running the program, only stopping when a spy-point is
reached or the program terminates. This allows the user to follow the execution at
a higher level than exhaustive tracing.
n: Nodebug
Turns off debug mode.
99
q: Quasi-skip
This is like Skip except that it does not mask out spy points.
r: Retry (fail)
Transfers to the Call port of the current goal. Note, however, that side effects,
such as database modifications etc., are not undone.
s: Skip
Causes tracing to be turned off for the entire execution of the procedure. Thus,
nothing is seen until control comes back to that procedure, either at the Success
or the Failure port.
Other predicates that are useful in debugging are:
100
untrace(_P_r_e_d_s)
where Preds is a term _P/_N, where _P is a predicate name and _N its arity, or a list
of such terms. Turns off tracing on the specified predicates. _P_r_e_d_s must be
instantiated at the time of the call.
spy(_P_r_e_d_s)
where Preds is a term _P/_N, where _P is a predicate name and _N its arity, or a list
of such terms. Sets spy points on the specified predicates. _P_r_e_d_s must be instan-
tiated at the time of the call.
nospy(Preds)
where Preds is a term _P/_N, where _P is a predicate name and _N its arity, or a list
of such terms. Removes spy points on the specified predicates. _P_r_e_d_s must be
instantiated at the time of the call.
101
debug
Turns on debugging mode. This causes subsequent execution of predicates with trace
or spy points to be traced, and is a no-op if there are no such predicates. The
predicates _t_r_a_c_e/1 and _s_p_y/1 cause debugging mode to be turned on automatically.
nodebug
Turns off debugging mode. This causes trace and spy points to be ignored.
debugging
Displays information about whether debug mode is on or not, and lists predicates
that have trace points or spy points set on them.
tracepreds(_L)
Binds _L to a list of terms _P/_N where the predicate _P of arity _N has a trace point
set on it.
102
spypreds(_L)
Binds _L to a list of terms _P/_N where the predicate _P of arity _N has a spy point set
on it.
There is one known bug in the package: attempts to set trace points, via _t_r_a_c_e/1,
on system and library predicates that are used by the trace package can cause bizarre
behaviour.
_6._2. _L_o_w _L_e_v_e_l _T_r_a_c_i_n_g
SB-Prolog also provides a facility for low level tracing of execution. This can be
activated by invoking the simulator with the -T option, or through the predicate
_t_r_a_c_e/0. It causes trace information to be printed out at every call (including those
to system trap handlers). The volume of such trace information can very become large
very quickly, so this method of tracing is not recommended in general.
103
Low level tracing may be turned off using the predicate _u_n_t_r_a_c_e/0.
_7. _T_h_e _S_i_m_u_l_a_t_o_r
The simulator resides in the SB-Prolog system directory _s_i_m. The following sec-
tions describe various aspects of the simulator.
_7._1. _I_n_v_o_k_i_n_g _t_h_e _S_i_m_u_l_a_t_o_r
The simulator is invoked by the command
sbprolog _b_c__f_i_l_e
where _b_c__f_i_l_e is a byte code file resulting from the compilation of a Prolog program.
In almost all cases, the user will wish to interact with the SB-Prolog _q_u_e_r_y _e_v_a_l_u_a_t_o_r,
in which case _b_c__f_i_l_e will be $_r_e_a_d_l_o_o_p, and the command will be
104
sbprolog /
_\ path \
//\$readloop
where /
_\_p_a_t_h\
/ is the path to the directory containing the command interpreter $_r_e_a_d_l_o_o_p.
This directory, typically, is the system directory _m_o_d_l_i_b.
The command interpreter reads in a query typed in by the user, evaluates it and
prints the answer(s), repeating this until it encounters an end-of-file (the standard
end-of-file character on the system, e.g. ctrl-D), or the user types in _e_n_d__o_f__f_i_l_e or
_h_a_l_t.
The user should ensure that the the directory containing the executable file _s_i_m
(typically, the system directory _s_i_m) is included in the shell variable _p_a_t_h; if not,
the full path to the simulator will have to be specified.
In general, the simulator may be invoked with a variety of options, as follows:
105
sbprolog -_o_p_t_i_o_n_s _b_c__f_i_l_e
or
sbprolog -_o_p_t_i_o_n<1> -_o_p_t_i_o_n<2> ... -_o_p_t_i_o_n<_n> _b_c__f_i_l_e
The options recognized by the simulator are described below.
When called with a byte code file _b_c__f_i_l_e, the simulator begins execution with the
first clause in that file. The first clause in such a file, therefore, should be a
clause without any arguments in the head (otherwise, the simulator will attempt to
dereference argument pointers in the head that are really pointing into deep space, and
usually come to a sad end). If the user is executing a file in this manner rather than
using the command interpreter, he should also be careful to include the undefined predi-
cate handler `_$_u_n_d_e_f_i_n_e_d__p_r_e_d'/1, which is normally defined in the file
_m_o_d_l_i_b/$_i_n_i_t__s_y_s._P.
106
_7._2. _S_i_m_u_l_a_t_o_r _O_p_t_i_o_n_s
The following is a list of options recognized by the simulator.
T Generates a trace at entry to each called routine.
d Produces a disassembled dump of _b_c__f_i_l_e into a file named `dump.pil' and exits.
n Adds machine addresses when producing trace and dump.
s Maintains information for the builtin _s_t_a_t_i_s_t_i_c_s/0. Default: off.
m _s_i_z_e
Allocates _s_i_z_e words (4 bytes) of space to the local stack and heap together.
Default: 100000.
p _s_i_z_e
Allocates _s_i_z_e words of space to the program area. Default: 100000.
107
b _s_i_z_e
Allocates _s_i_z_e words of space to the trail stack. Default: _m/5, where _m is the
amount of space allocated to the local stack and heap together. This parameter, if
specified, must follow the -m parameter.
As an example, the command
sbprolog -s -p 60000 -m 150000 \$readloop
starts the simulator executing the command interpreter with 60000 bytes of program
space, 150000 bytes of local and global stack space and (by default) 30000 bytes of
trail stack space; the _s option also results in statistics information being maintained.
_7._3. _I_n_t_e_r_r_u_p_t _H_a_n_d_l_i_n_g
108
SB-Prolog provides a facility for exception handling using user-definable interrupt
handlers. This can be used both for external interrupts, e.g. those generated from the
keyboard by the user or from signals other processes; or internal traps, e.g. those
caused by stack overflows, encountering undefined predicates, etc. For example, the
``undefined predicate'' interrupt is handled, by default, by the predicate
`_$_u_n_d_e_f_i_n_e_d__p_r_e_d'/1, which is defined in the file _m_o_d_l_i_b/$_i_n_i_t__s_y_s._P. The default
action on encountering an undefined predicate is to attempt to dynamically load a file
whose name matches that of the undefined predicate. However, the user may easily alter
this behaviour by redefining the undefined predicate handler.
_8. _T_h_e _C_o_m_p_i_l_e_r
The compiler translates Prolog source files into byte-code object files. It is written
entirely in Prolog. The byte code for the compiler can be found in the SB-Prolog system
109
directory _c_m_p_l_i_b, with the source code resident in _c_m_p_l_i_b/_s_r_c.
Byte code files may be concatenated together to produce other byte code files.
Thus, for example, if _f_o_o_1 and _f_o_o_2 are byte code files resulting from the compilation
of two Prolog source programs, then the file _f_o_o, obtained by executing the shell com-
mand
cat foo1 foo2 > foo
is a byte code file as well, and may be loaded and executed. In this case, loading and
executing the file _f_o_o would give the same result as loading _f_o_o_1 and _f_o_o_2 separately,
which in turn would be the same as concatenating the original source files and compiling
this larger file. This makes it easier to compile large programs: one need only break
them into smaller pieces, compile the individual pieces, and concatenate the byte files
together.
110
The following sections describe the various aspects of the compiler in more detail.
_8._1. _S_t_r_u_c_t_u_r_e _o_f _t_h_e _C_o_m_p_i_l_e_r
The compilation of a Prolog program proceeds in four phases. In the first phase, the
source program is read in and passed through a preprocessor. The output of the prepro-
cessor is essentially another Prolog source program. Next, this program is transformed
into an internal representation (essentially an annotated abstract syntax tree). The
third phase involves generating WAM ``assembly'' code and peephole optimization.
Finally, the WAM assembly code is processed by an assembler which generates byte code.
_8._2. _I_n_v_o_k_i_n_g _t_h_e _C_o_m_p_i_l_e_r
The compiler is invoked through the Prolog predicate _c_o_m_p_i_l_e:
| ?- compile(_I_n_F_i_l_e [, _O_u_t_F_i_l_e ] [, _O_p_t_i_o_n_s_L_i_s_t ]).
111
where optional parameters are enclosed in brackets. _I_n_F_i_l_e is the name of the input
(i.e. source) file; _O_u_t_F_i_l_e is the name of the output file (i.e. byte code) file;
_O_p_t_i_o_n_s_L_i_s_t is a list of compiler options (see below).
The input and output file names must be Prolog atoms, i.e. either begin with a
lower case letter or dollar sign `$', and consist only of letters, digits, and under-
scores; or, be enclosed within single quotes. If the output file name is not specified,
it defaults to _I_n_F_i_l_e.out. The list of options, if specified, is a Prolog list, i.e. a
term of the form
[ _o_p_t_i_o_n<1>, _o_p_t_i_o_n<2>, ..., _o_p_t_i_o_n<_n> ].
If left unspecified, it defaults to the empty list [].
In fact, the output file name and the options list may be specified in any order.
Thus, for example, the queries
112
| ?- compile('/usr/debray/foo', foo_out, [v]).
and
| ?- compile('/usr/debray/foo', [v], foo_out).
are equivalent, and specify that the Prolog source file `/_u_s_r/_d_e_b_r_a_y/_f_o_o' is to be com-
piled in verbose mode (see ``Compiler Options'' below), and that the byte code is to be
generated into the file _f_o_o__o_u_t.
The _c_o_m_p_i_l_e predicate may also be called with a fourth parameter:
| ?- compile(_I_n_F_i_l_e, _O_u_t_F_i_l_e, _O_p_t_i_o_n_s_L_i_s_t, _P_r_e_d_L_i_s_t).
where _I_n_F_i_l_e, _O_u_t_F_i_l_e and _O_p_t_i_o_n_s_L_i_s_t are as before; _c_o_m_p_i_l_e/4 unifies _P_r_e_d_L_i_s_t with a
list of terms _P/_N denoting the predicates defined in _I_n_F_i_l_e, where _P is a predicate name
and _N its arity. _P_r_e_d_L_i_s_t, if specified, is usually given as an uninstantiated variable;
its principal use is for setting trace points on the predicates in the file (see Section
6), e.g. by executing
| ?- compile('/usr/debray/foo', foo_out, [v], L), load(foo_out), trace(L).
113
Notice that _P_r_e_d_L_i_s_t can only appear in _c_o_m_p_i_l_e/4.
_8._3. _C_o_m_p_i_l_e_r _O_p_t_i_o_n_s
The following options are currently recognized by the compiler:
a Specifies that an ``assembler'' file is to be created. The name of the assembler
file is obtained by appending ``.asl'' to the source file name. While the writing
out of assembly code slows down the compilation process to some extent, it allows
the assembler to do a better job of optimizing away indirect subroutine linkages
(since in this case the assembler has assembly code for the entire program to work
with at once, not just a single predicate). This results in code that is faster
and more compact.
d Dumps expanded macros to the user (see Section 10).
114
e Expand macros (see Section 10).
i Specifies that indexes are to be generated. The pragma file (see Section 12)
corresponding to the source file is consulted for information regarding predicates
which should have indexes constructed, and the arguments on which indexes are to be
constructed.
t If specified, turns off assembler optimizations that eliminate indirect branches
through the symbol table in favour of direct branches. This is useful in debugging
compiled code. It is _n_e_c_e_s_s_a_r_y if the extension table feature is to be used.
v If specified, compiles in ``verbose'' mode, which causes messages regarding pro-
gress of compilation to be printed out.
115
_8._4. _A _N_o_t_e _o_n _C_o_d_i_n_g _f_o_r _E_f_f_i_c_i_e_n_c_y
The SB-Prolog system tends to favour programs that are relatively pure. Thus, for
example, _a_s_s_e_r_ts tend to be quite expensive, encouraging the user to avoid them if pos-
sible. This section points out some syntactic constructs that lead to the generation of
efficient code. These involve (_i) avoiding the creation of backtrack points; and (_i_i)
minimizing data movement between registers. Optimization of logic programs is an area
of ongoing research, and we expect to enhance the capabilities of the system further in
future versions.
_8._4._1. _A_v_o_i_d_i_n_g _C_r_e_a_t_i_o_n _o_f _B_a_c_k_t_r_a_c_k _P_o_i_n_t_s
Since the creation of backtrack points is relatively expensive, program efficiency
may be improved substantially by using constructs that avoid the creation of backtrack
points where possible. The SB-Prolog compiler recognizes conditionals involving certain
116
complementary inline tests, and generates code that does not create choice points for
such cases. Two inline tests _p(_X~) and _q(_X~) are complementary if and only if _p(_X~) =_
_n_o_t(_q(_X~)). For example, the literals `_X > _Y' and `_X =< _Y' are complementary. At this
point, complementary tests are recognized as such only if their argument tuples are
identical. The inline predicates that are treated in this manner, with their
corresponding complementary literals, are shown in Table 3. The syntactic constructs
_________________________________________
_I_n_l_i_n_e _T_e_s_t _C_o_m_p_l_e_m_e_n_t_a_r_y _T_e_s_t
_________________________________________
>/2 =</2
_________________________________________
=</2 >/2
_________________________________________
>=/2 </2
_________________________________________
</2 >=/2
_________________________________________
=:=/2 =\=/2
_________________________________________
=\=/2 =:=/2
_________________________________________
var/1 nonvar/1
_________________________________________
nonvar/1 var/1
_________________________________________
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Table 3: Complementary tests recognized by the compiler
117
recognized are:
(_i) Disjuncts of the form
_h_e_a_d :- (( _t_e_s_t(_X~), ... ) ; ( not(_t_e_s_t(_X~)), ...)).
or
_h_e_a_d :- (( _t_e_s_t(_X~), ... ) ; ( _c_o_m_p__t_e_s_t(_X~), ...)).
where _t_e_s_t is one of the inline tests in the table above, and _c_o_m_p__t_e_s_t the
corresponding complementary test (note that the arguments to _t_e_s_t and _c_o_m_p__t_e_s_t
have to be identical).
(_i_i) Conditionals of the form
_h_e_a_d :- (_t_e_s_t<1>, ... , _t_e_s_t<_n>) -> _T_r_u_e__C_a_s_e ; _F_a_l_s_e__C_a_s_e.
or
_h_e_a_d :- (_t_e_s_t<1>; ... ; _t_e_s_t<_n>) -> _T_r_u_e__C_a_s_e ; _F_a_l_s_e__C_a_s_e.
118
where each _t_e_s_t<_i> is an inline test, as mentioned in the table above.
The code generated for these cases involves a test and conditional branch, and no
choice point is created. We expect future versions of the translator to recognize a
wider class of complementary tests.
Notice that this discourages the use of explicit cuts. For example, whereas a
choice point will be created for
part(M,[E|L],U1,U2) :-
((E =< M, !, U1 = [E|U1a], U2 = U2a) ;
(U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
no choice point will be created for either
part(M,[E|L],U1,U2) :-
(E =< M ->
(U1 = [E|U1a], U2 = U2a) ;
(U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
or
119
part(M,[E|L],U1,U2) :-
((E =< M, U1 = [E|U1a], U2 = U2a) ;
(E > M, U1 = U1a, U2 = [E|U2a])),
part(M,L,U1a,U2a).
Thus, either of the two later versions will be more efficient than the version with the
explicit cut.
_8._4._2. _M_i_n_i_m_i_z_i_n_g _D_a_t_a _M_o_v_e_m_e_n_t _B_e_t_w_e_e_n _R_e_g_i_s_t_e_r_s
Data movement between registers for parameter passing may be minimized by leaving
variables in the same argument position wherever possible. Thus, the clause
p(X,Y) :- p1(X,Y,0).
is preferable to
p(X,Y) :- p1(0,X,Y).
because the first definition leaves the variables _X and _Y in the same argument positions
(first and second, respectively), while the second definition does not.
120
_8._5. _A_s_s_e_m_b_l_y
The SB-Prolog assembler can be invoked by loading the compiler and using the predi-
cate $_a_s_m/3:
| ?- $asm(_I_n_F_i_l_e, _O_u_t_F_i_l_e, _O_p_t_i_o_n_s_L_i_s_t).
where _I_n_F_i_l_e is a Prolog atom which is the name of a WAM assembly source file (e.g. the
``.asl'' file generated when a Prolog program is compiled with the ``a'' option), _O_u_t_-
_F_i_l_e is an atom which is the name of the intended byte code file, and _O_p_t_i_o_n_s_L_i_s_t is a
list of options. The options recognized by the assembler are:
v ``Verbose'' mode. Prints out information regarding progress of assembly.
t ``Trace''. If specified, the assembler generates code to force procedure calls to
branch indirectly via the symbol table, instead of using a direct branch. This is
Useful for tracing compiled code. It is _n_e_c_e_s_s_a_r_y if the extension table feature
121
is to be used.
The assembler is intended primarily to support the compiler, so the assembly language
syntax is quirky in places. The interested reader is advised to look at the assembly
files resulting from compilation with the ``a'' option for more on SB-Prolog assembler
syntax.
_9. _M_o_d_u_l_e_s
To describe how modules (or maybe more properly, just libraries) are currently sup-
ported in our system, we must describe the _$_u_n_d_e_f_i_n_e_d__p_r_e_d/1 interrupt handler. The
system keeps a table of modules and routines that are needed from each. When a predi-
cate is found to be undefined, the table is searched to see if it is defined by some
module. If so, that module is loaded (if it hasn't been previously loaded) and the
association is made between the routine name as defined in the module, and the routine
122
name as used by the invoker.
The table of modules and needed routines is:
defined_mods(_M_o_d_n_a_m_e, [_p_r_e_d<1>/_a_r_i_t_y<1>, ..., _p_r_e_d<_n>/_a_r_i_t_y<_n>]).
where _M_o_d_n_a_m_e is the name of the module. The module exports _n predicate definitions.
The first exported pred is of arity _a_r_i_t_y<>1, and needs to be invoked by the name of
_p_r_e_d<1>.
The table of modules that have already been loaded is given by
loaded_mods(_M_o_d_n_a_m_e).
A module is a file of predicate definitions, together with a fact defining a list of
predicates exported by that module, and a set of facts, each of which specifies, for
some other module, the predicates imported from that module. For example, consider a
module name `_p'. It contains a single fact, named _p__e_x_p_o_r_t, that is true of the list of
123
predicate/arity's that are exported. E.g.
p_export([p1/2, p2/4])
indicates that the module _p exports the predicates _p_1/2 and _p_2/4. For each module _m
which contains predicates needed by the module _p, there is a fact for _p__u_s_e, describing
what module is needed and the names of the predicates defined there that are needed.
For example, if module _p needs to import predicates _i_p_1/2 and _i_p_2/3 from module _q, there
would be a fact
p_use(q,[ip1/2, ip2/3])
where _q is a module that exports two predicates: one 2-ary and one 3-ary. This list
corresponds to the export list of module _q.
The correspondence between the predicates in the export list of an exporting
module, and those in the import or _u_s_e list of a module which imports one or more of
them, is by position, i.e. the predicate names at the exporting and importing names may
124
be different, and the association between names in the two lists is by the position in
the list. If the importing module does not wish to import one or more of the predicates
exported by the exporting module, it may put an anonymous variable in the corresponding
position in its _u_s_e list. Thus, for example, if module _p above had wished to import
only the predicate _i_p_2/3 from module _q, the corresponding use fact would be
p_use(q, [_, ip2/3]).
The initial set of predicates and the modules from which they are to be loaded is
set up by an initial call to $_p_r_o_r_c/0 (see the SB-Prolog system file
_m_o_d_l_i_b/_s_r_c/$_p_r_o_r_c._P). This predicate makes initial calls to the predicate $define_mod
which set up the tables described above so that the use of standard predicates will
cause the correct modules to be loaded in the _$_u_n_d_e_f_i_n_e_d__p_r_e_d routine, and the correct
names to be used.
125
_1_0. _M_a_c_r_o_s
SB-Prolog features a facility for the definition and expansion of macros that is
fully compatible with the runtime system. Its basic mechanism is a simple partial
evaluator. It is called by both _c_o_n_s_u_l_t and _c_o_m_p_i_l_e, so that macro expansion occurs
independently of whether the code is interpreted or compiled (but not when asserted).
Moreover, the macro definitions are retained as clauses at runtime, so that invocation
of macros via _c_a_l_l/1 at runtime (or from asserted clauses) does not pose a problem.
This means, however, that if the same macro is used in many different files, it will be
loaded more than once, thus leading to wasetd space. This ought to be thought about and
fixed.
The source for the macro expander is in the SB-Prolog system file
_m_o_d_l_i_b/_s_r_c/$_m_a_c._P.
126
_1_0._1. _D_e_f_i_n_i_n_g _M_a_c_r_o_s
`Macros', or predicates to be evaluated at compile-time, are defined by clauses of
the form
Head ::- Body
where facts have `true' as their body. The partial evaluator will expand any call to a
predicate defined by ::-/2 that unifies with the head of only one clause in ::-/2. If a
call unifies with the head of more than one clause in ::-/2, it will not be expanded
Notice that this is not a fundamental restriction, since `;' is permitted in the body of
a clause. The partial evaluator also converts each definition of the form
Head ::- Body.
to a clause of the form
Head :- Body.
127
and adds this second clause to the other ``normal'' clauses that were read from the
file. This ensures that calls to the macro at runtime, e.g. through _c_a_l_l/1 or from
unexpanded calls in the program do not cause any problems.
The partial evaluator is actually a Prolog interpreter written `purely' in Prolog,
i.e., variable assignments are explicitly handled. This is necessary to be able to han-
dle impure constructs such as `var(X), X=a'. As a result this is a _v_e_r_y _s_l_o_w Prolog
evaluator.
Since naive partial evaluation can go into an infinite loop, SB-Prolog's partial
evaluator maintains a depth-bound and will not expand recursive calls deeper than that.
The depth is determined by the globalset predicate $_m_a_c__d_e_p_t_h. The default value for
$_m_a_c__d_e_p_t_h is 50 This can be changed to some other value _n by executing
| ?- globalset($mac_depth(_n)).
128
_1_0._2. _M_a_c_r_o _E_x_p_a_n_d_e_r _O_p_t_i_o_n_s
The following options are recognized by the macro expander:
d Dumps all clauses to the user after expansion. Useful for debugging.
e Expand macros. If omitted, the expander simply converts each ::-/2 clause to a
normal :-/2 clause.
v ``Verbose'' mode. Prints macros that are/are not being expanded.
_1_1. _E_x_t_e_n_s_i_o_n _T_a_b_l_e_s
Extension tables store the calls and answers for a predicate. If a call has been
made before, answers are retrieved from the extension table instead of being recomputed.
Extension tables provide a caching mechanism for Prolog. In addition, extension tables
affect the termination characteristics of recursive programs. Some Prolog programs,
129
which are logically correct, enter an infinite loop due to recursive predicates. An
extension table saved on recursive predicates can find all answers (provided the set of
such answers is finite) and terminate for some logic programs for which Prolog's evalua-
tion strategy enters an infinite loop. Iterations over the extension table execution
strategy provides complete evaluation of queries over function-free Horn clause pro-
grams.
To be able to use the simple extension table evaluation on a set of predicates, the
source file should either be consulted, or compiled with the t option (the t option
keeps the assembler from optimizing subroutine linkage and allows the extension table
facility to intercept calls to predicates).
To use extension table execution, all predicates that are to be saved in the exten-
sion table must be passed to _e_t/1. For example,
| ?- et([pred1/1, pred2/2]), et(pred3/2)
130
will set up ``ET-points'' for the for predicates _p_r_e_d_1/1, _p_r_e_d_2/2 and _p_r_e_d_3/2, which
will cause extension tables for these predicates to be maintained during execution. At
the time of the call to _e_t/1, these predicates must be defined, either by having been
loaded, or through _c_o_n_s_u_l_t.
The predicate _n_o_e_t/1 takes a list of predicate/arity pairs for which ET-points
should be deleted. Notice that once an ET-point has been set up for a predicate, it
will be maintained unless explicitly deleted via _n_o_e_t/1. If the definition of a predi-
cate which has an ET-point defined is to be updated, the ET-point must first be deleted
via _n_o_e_t/1. The predicate can then be reloaded and a new ET-point established. This is
enforced by the failure of the goal ``et(P/N)'' if an ET-point already exists for the
argument predicate. In this case, the following error message will be displayed:
*et* already defined for: P/N
131
There are, in fact, two extension table algorithms: a simple one, which simply
caches calls to predicates which have ET-points defined; and a complete ET algorithm,
which iterates the simple extension table algorithm until no more answers can be found.
The simple algorithm is more efficient than the complete one; however, the simple algo-
rithm is not complete for certain especially nasty forms of mutual recursion, while the
complete algorithm is. To use the simple extension table algorithm, predicates can sim-
ply be called as usual. The complete extension table algorithm may be used via the
query
| ?- et_star(Query).
The extension table algorithm is intended for predicates that are ``essentially pure'',
and results are not guaranteed for code using impure code. The extension table algo-
rithm saves only those answers which are not instances of what is already in the table,
and uses these answers if the current call is an instance of a call already made. For
132
example, if a call _p(_X, _Y), with _X and _Y uninstantiated, is encountered and inserted
into the extension table, then a subsequent call _p(_X, _b) will be computed using the
answers for _p(_X, _Y) already in the extension table. Notice that this might not work if
var/nonvar tests are used on the second argument in the evaluation of _p.
Another problem with using impure code is that if an ET predicate is cut over, then
the saved call implies that all answers for that predicate were computed, but there are
only partial results in the ET because of the cut. So on a subsequent call the incom-
plete extension table answers are used when all answers are expected.
Example:
r(X,Y) :- p(X,Y),q(Y,Z),!,fail.
| ?- r(X,Y) ; p(X,Y).
Let p be an ET predicate whose evaluation yields many tuples. In the evaluation of the
query, r(X,Y) makes a call to p(X,Y). Assuming that there is a tuple such that q(Y,Z)
succeeds with the first p tuple then the evaluation of p is cut over. The call to p(X,Y)
133
in the query uses the extension table because of the previous call in the evaluation of
r(X,Y). Only one answer is found, whereas the relation p contains many tuples, so the
computation is not complete. Note that "cuts" used within the evaluation of an ET
predicate are ok, as long as they don't cut over the evaluation of another ET predicate.
The evaluation of the predicate that uses cuts does not cut over any et processing (such
as storing or retrieving answers) so that the tuples that are computed are saved. In the
following example, the ET is used to generate prime numbers where an ET point is put on
prime/1.
Example:
prime(I) :- globalset(globalgenint(2)),fail. /* Generating Primes */
prime(I) :- genint(I), not(div(I)).
div(I) :- prime(X), 0 is I mod X.
genint(N) :-
repeat,
globalgenint(N),
N1 is N+1,
globalset(globalgenint(N1)).
134
The following summarizes the library predicates supporting the extension table facility:
et(_L)
Sets up an ET-point on the predicates _L, which causes calls and anwers to these
predicates to be saved in an ``extension table''. _L is either a term _P_r_e_d/_A_r_i_t_y,
where _P_r_e_d is a predicate symbol and _A_r_i_t_y its arity, or a set of such terms
represented as a list. _L must be instantiated, and the predicates specified in it
defined, at the time of the call to _e_t/1. Gives error messages and fails if any of
the predicates in _L is undefined, or if an ET-point already exists on any of them;
in this case, no ET-point is set up on any of the predicates in _L.
et_star(Goal)
Invokes the complete extension table algorithm on the goal _G_o_a_l.
135
_e_t__p_o_i_n_t_s(_L)
Unifies _L with a list of predicates for which an ET-point is defined. _L is the
empty list [] if there are no ET-points defined.
noet(_L)
Deletes ET-points on the predicates specified in _L. _L is either a term _P/_N, where
_P is the name of a predicate and _N its arity, or a set of such terms represented as
a list. Gives error messages and fails if there is no ET-point on any of the
predicates specified in _L. Deleting an ET-point for a predicate also removes the
calls and answers stored in the extension table for that predicate. The extension
tables for all predicates for which ET-points are defined may be deleted using
_e_t__p_o_i_n_t_s/1 in cojnunction with _n_o_e_t/1.
_L must be instantiated at the time of the call to _n_o_e_t/1.
136
et_remove(_L)
Removes both calls and answers for the predicates specified in _L. In effect, this
results in the extension table for these predicates to be set to empty. _L must be
instantiated at the time of the call to either a term _P/_N, where _P is a predicate
with arity _N, or a list of such terms. An error occurs if any of the predicates in
_L does not have an ET-point set.
All extension tables can be emptied by using _e_t__p_o_i_n_t_s/1 in conjunction with
_e_t__r_e_m_o_v_e/1.
et_answers(_P/_N, _T_e_r_m)
Retrieves the answers stored in the extension table for the predicate _P/_N in _T_e_r_m
one at a time. _T_e_r_m is of the form _P(_t<1>, ..., _t<_N>). An error results and
_e_t__a_n_s_w_e_r_s/2 fails if _P/_N is not fully specified (ground), or if _P/_N does not have
137
an ET-point set.
et_calls(_P/_N, _T_e_r_m)
Retrieves the calls stored in the extension table for the predicate _P/_N in _T_e_r_m one
at a time. _T_e_r_m is of the form _P(_t<1>, ..., _t<_N>). An error results and
_e_t__c_a_l_l_s/2 fails if _P/_N is not fully specified (ground), or if _P/_N does not have an
ET-point set.
_1_2. _O_t_h_e_r _L_i_b_r_a_r_y _U_t_i_l_i_t_i_e_s
The SB-Prolog library contains various other utilities, some of which are listed
below.
$append(_X, _Y, _Z)
138
Succeeds if list _Z is the concatenation of lists _X and _Y.
$member(_X, _L)
Checks whether _X unifies with any element of list _L, succeeding more than once if
there are multiple such elements.
$memberchk(_X, _L)
Similar to $_m_e_m_b_e_r/2, except that $_m_e_m_b_e_r_c_h_k/2 is deterministic, i.e. does not
succeed more than once for any call.
$reverse(_L, _R)
Succeeds if _R is the reverse of list _L. If _L is not a fully determined list, i.e.
if the tail of _L is a variable, this predicate can succeed arbitrarily many times.
$merge(_X, _Y, _Z)
139
Succeeds if _Z is the list resulting from ``merging'' lists _X and _Y, i.e. the ele-
ments of _X together with any element of _Y not occurring in _X. If _X or _Y contain
duplicates, _Z may also contain duplicates.
$absmember(_X, _L)
Similar to $_m_e_m_b_e_r/2, except that it checks for identity (through ==/2) rather than
unifiability (through =/2) of _X with elements of _L.
$nthmember(_X, _L, _N)
Succeeds if the _N[th.] element of the list _L unifies with _X. Fails if _N is greater
than the length of _L. Either _X and _L, or _L and _N, should be instantiated at the
time of the call.
$member2(_X, _L)
140
Checks whether _X unifies with any of the actual elements of _L. The only difference
between this and $_m_e_m_b_e_r/2 is on lists with a variable tail, e.g. [a, b, c | _ ]:
while $_m_e_m_b_e_r/2 would insert _X at the end of such a list if it did not find it,
$_m_e_m_b_e_r_2/2 only checks for membership but does not insert it into the list if it is
not there.
_1_3. _P_r_a_g_m_a _F_i_l_e_s
Users may specify pragma information about SB-Prolog programs in a file called the
_p_r_a_g_m_a _f_i_l_e for the program. The pragma file corresponding to a Prolog source file _f_o_o
is a file _f_o_o._d_e_f which is either in the same directory as the source file, or is in a
subdirectory _d_e_f_s in the directory containing the source file. In other words, relative
to the directory containing the source file _f_o_o, the pragma file can be either _f_o_o._d_e_f
or _d_e_f_s/_f_o_o._d_e_f.
141
Pragma information in such a file is specified as a set of facts _p_r_a_g/_3. The first
and second arguments are, respectively, the name and arity of the predicate for which
information is being specified. The third argument is the pragma being specified, and
can be either a term, or a list of terms. Thus, for example, to specify that an index
is to be created on the first argument position for a predicate _b_a_r/3 in the file _f_o_o,
we would enter, in a file _f_o_o._d_e_f, the fact ``prag(bar, 3, index)'' or ``prag(bar, 3,
[index])''.
The pragma information that may be specified is limited, at this point, to informa-
tion about indexing. If an index is to be created on argument _n of a predicate, the
corresponding pragma is a term ``index(_n)''. In the special case where _n = 1, the
pragma ``_i_n_d_e_x(1)'' may be abbreviated to ``_i_n_d_e_x''.
142
Acknowledgements
A large number of people were involved, at some time or another, with the Logic
Programming group at SUNY, Stony Brook, and deserve credit for bringing the SB-Prolog
system to its present form. The following names, in particular, ought to be mentioned:
David Scott Warren, Weidong Chen, Suzanne Dietrich, Sanjay Manchanda, Jiyang Xu and
David Znidarsic. The author is also grateful to Fernando Pereira for permission to use
material from the C-Prolog manual for the descriptions of Prolog syntax and many of the
builtins. junk
53
_A_p_p_e_n_d_i_x _1: _E_v_a_l_u_a_b_l_e _P_r_e_d_i_c_a_t_e_s _o_f _S_B-_P_r_o_l_o_g
An entry of ``B'' indicates a builtin predicate, ``I'' an inline predicate, and
``L'' a library predicate. A ``P'' indicates that the predicate is handled by the
preprocessor during compilation and/or consulting.
(L) _$undefined_pred/1 ......... 10
(L) compile/1 .................. 11
(L) compile/2 .................. 11
(L) compile/3 .................. 11
(L) compile/4 .................. 11
(B) load/1 ..................... 13
(L) consult/1 .................. 15
(L) consult/2 .................. 15
(P) :-/1 ....................... 18
(L) op/3 ....................... 29
(B) see/1 ...................... 40
(B) seen ....................... 41
(B) tell/1 ..................... 41
(B) telling/1 .................. 41
(B) told/0 ..................... 41
(B) $exists/1 .................. 41
(L) read/1 ..................... 42
(L) write/1 .................... 42
(L) display/1 .................. 43
(L) writeq/1 ................... 43
54
(L) print/1 .................... 43
(B) writename/1 ................ 43
(B) writeqname/1 ............... 43
(B) nl/0 ....................... 44
(B) get0/1 ..................... 44
(B) get/1 ...................... 44
(B) put/1 ...................... 44
(B) tab/1 ...................... 45
(I) is/2 ....................... 48
(L) eval/2 ..................... 49
(I) =:=/2 ...................... 50
(I) =\=/2 ...................... 50
(I) </2 ........................ 50
(I) >/2 ........................ 50
(I) =</2 ....................... 51
(I) >=/2 ....................... 51
(B) floor/2 ..................... 52
(B) floatc/3 .................... 52
(B) exp/2 ....................... 53
(B) square/2 .................... 53
(B) sin/2 ....................... 53
(I) `,'/2 ...................... 54
(I) `;'/2 ...................... 54
(I) true/0 ..................... 54
(I) =/2 ........................ 54
(P) !/0 ........................ 55
(P) not/1 ...................... 55
(P) ->/2 ....................... 56
(L) repeat/0 ................... 56
(I) fail/0 ..................... 56
(I) var/1 ...................... 56
(I) nonvar/1 ................... 57
(B) atom/1 ..................... 57
(B) integer/1 .................. 57
(B) real/1 ...................... 57
(B) number/1 ................... 57
55
(B) atomic/1 ................... 58
(B) structure/1 ................. 58
(L) functor/3 .................. 58
(B) arg/3 ...................... 59
(L) =../2 ...................... 59
(B) name/2 ..................... 60
(P) call/1 ..................... 60
(B) conlength/2 ................ 62
(L) setof/3 .................... 63
(L) bagof/3 .................... 64
(B) ==/2 ....................... 66
(B) \==/2 ...................... 67
(B) @</2 ....................... 67
(B) @>/2 ....................... 67
(B) @=</2 ...................... 68
(B) @>=/2 ...................... 68
(B) compare/3 .................. 68
(L) sort/2 ...................... 69
(L) alloc_perm/2 ............... 71
(L) alloc_heap/2 ............... 71
(L) $alloc_heap/5 .............. 71
(L) trimbuff/3 ................. 72
(L) $trim_buff/4 ............... 73
(L) assert/1 ................... 76
(L) assert/2 ................... 76
(L) asserti/2 .................. 78
(L) asserta/1 ................... 78
(L) asserta/2 ................... 78
(L) assertz/1 ................... 79
(L) assertz/2 ................... 79
(L) assert_union/2 ............. 79
(L) assert/4 ................... 80
(L) retract/1 .................. 81
(L) abolish/1 .................. 82
(L) abolish/2 .................. 82
(L) call_ref/2 ................. 82
56
(L) call_ref/3 ................. 83
(L) $db_new_prref/3 ............ 84
(L) $db_assert_fact/5 .......... 84
(L) $db_add_clref/7 ............ 85
(L) $db_call_prref/2 ........... 86
(L) $db_call_prref_s/2 ......... 86
(L) $db_get_clauses/3 .......... 87
(L) $db_kill_clause/1 .......... 87
(L) break/0 ..................... 88
(B) abort/0 ..................... 89
(B) save/1 ...................... 89
(B) restore/1 ................... 89
(B) cputime/1 .................. 90
(L) $getenv/2 .................. 90
(B) statistics/0 ............... 90
(B) symtype/2 .................. 91
(B) system/1 ................... 92
(B) syscall/3 .................. 92
(L) globalset/1 ................ 94
(L) gennum/1 ................... 95
(L) gensym/2 ................... 95
(L) trace/1 .................... 95
(L) untrace/1 .................. 101
(L) spy/1 ...................... 101
(L) nospy/1 .................... 101
(L) debug/0 .................... 102
(L) nodebug/0 .................. 102
(L) debugging/0 ................ 102
(L) tracepreds/1 ............... 102
(L) spypreds/1 ................. 103
(L) trace/0 .................... 103
(L) untrace/0 .................. 104
(P) ::-/2 ...................... 127
(L) et/1 ....................... 135
(L) et_star/1 .................. 135
(L) et_points/1 ................ 136
57
(L) noet/1 ..................... 136
(L) et_remove/1 ................ 137
(L) et_calls/2 ................. 138
(L) $append/3 .................. 139
(L) $member/2 .................. 139
(L) $reverse/2 ................. 139
(L) $merge/3 ................... 140
(L) $absmember/2 ............... 140
(L) $nthmember/3 ............... 140
_A_p_p_e_n_d_i_x _2: _A_d_d_i_n_g _B_u_i_l_t_i_n_s _t_o _S_B-_P_r_o_l_o_g
Adding a builtin involves writing the C code for the desired case and installing it
into the simulator. The files in the irectory _s_i_m/_b_u_i_l_t_i_n contain the C code for the
builtin predicates supported by the system. The following procedure is to be followed
when adding a builtin to the system:
58
_I. _I_n_s_t_a_l_l_i_n_g _C _C_o_d_e:
(1) Go to the directory _s_i_m/_b_u_i_l_t_i_n.
(2) Look at the #defines in the file _b_u_i_l_t_i_n._h, and choose a number _N_1 (between 0 and
255) which is not in use to be the builtin number for the new builtin.
(3) Add to the file _b_u_i_l_t_i_n._h the line
#define NEWBUILTIN _N_1
(4) The convention is that the code for builtin will be in a parameterless procedure
named _b__N_E_W_B_U_I_L_T_I_N. Modify the file _i_n_i_t__b_r_a_n_c_h._c in the directory _s_i_m/_b_u_i_l_t_i_n by
adding these lines:
extern int b_NEWBUILTIN();
and
set_b_inst ( NEWBUILTIN, b_NEWBUILTIN );
in the appropriate places.
59
(5) The builtins are compiled together into one object file, _b_u_i_l_t_i_n. Update the file
_M_a_k_e_f_i_l_e by appending the name of your object code file at the end of the line
``OBJS = ... '' and insert the appropriate commands to compile your C source file,
e.g.:
OBJS = [ ... _o_t_h_e_r _f_i_l_e _n_a_m_e_s ... ] newbuiltin.o
...
newbuiltin.o: $(HS)
cc $(CFLAGS) newbuiltin.c
(6) Execute the updated make file to create an updated object file _b_u_i_l_t_i_n.
(7) Go to the directory _s_i_m and execute _m_a_k_e to install the new file _b_u_i_l_t_i_n.
_I_I. _I_n_s_t_a_l_l_i_n_g _P_r_o_l_o_g _C_o_d_e:
Assume that the builtin predicate to be added is _n_e_w_b_u_i_l_t_i_n/4. The procedure for
installing the Prolog code for this is as follows:
60
(1) Go to the SB-Prolog system directory _l_i_b/_s_r_c, where the Prolog source for the
library routines is kept.
(2) Each builtin definition is of the form
pred( ... ) :- '_$builtin'(_N).
where _N is an integer, the builtin number of _p_r_e_d.
(3) Create a Prolog source file _n_e_w_b_u_i_l_t_i_n._P (notice correspondence with the name of
the predicate being defined) containing the definition
newbuiltin(A,B,C,D) :- '_$builtin'(_N_1).
where _N_1 is the builtin number of the predicate _n_e_w_b_u_i_l_t_i_n, obtained when instal-
ling the C code for the builtin (see above).
61
(4) Compile this Prolog predicate, using the simulator and the _c_o_m_p_i_l_e predicate, into
a file _n_e_w_b_u_i_l_t_i_n (notice correspondence with the name of the predicate being
defined) in the SB-Prolog directory _l_i_b.
62
TABLE OF CONTENTS
1 : Introduction .......................................................... 2
2 : Getting Started ....................................................... 5
2.1 : The Dynamic Loader Search Path .................................... 5
2.2 : System Directories ................................................ 7
2.3 : Invoking the Simulator ............................................ 8
2.4 : Executing Programs ................................................ 11
2.4.1 : Compiling Programs ........................................... 11
2.4.2 : Loading Byte Code Files ...................................... 13
2.4.3 : Consulting Programs .......................................... 15
2.5 : Execution Directives .............................................. 18
3 : Syntax ................................................................ 20
3.1 : Terms ............................................................. 20
3.2 : Operators ......................................................... 25
4 : SB-Prolog: Operational Semantics ...................................... 33
4.1 : Standard Execution Behaviour ...................................... 33
4.2 : Cuts and If-Then-Else ............................................. 34
4.3 : Unification of Floating Point Numbers ............................. 36
5 : Evaluable Predicates .................................................. 37
5.1 : Input and Output .................................................. 40
5.1.1 : File Handling ................................................ 40
5.1.2 : Term I/O ..................................................... 42
5.1.3 : Character I/O ................................................ 44
5.2 : Arithmetic ........................................................ 45
5.3 : Convenience ....................................................... 54
5.4 : Extra Control ..................................................... 55
5.5 : Meta-Logical ...................................................... 56
5.6 : Sets .............................................................. 62
5.7 : Comparison of Terms ............................................... 65
5.8 : Buffers ........................................................... 69
5.9 : Modification of the Program ....................................... 74
5.10 : Environmental .................................................... 88
5.11 : Global Values .................................................... 93
6 : Debugging ............................................................. 95
6.1 : High Level Tracing ................................................ 95
6.2 : Low Level Tracing ................................................. 103
7 : The Simulator ......................................................... 104
7.1 : Invoking the Simulator ............................................ 104
7.2 : Simulator Options ................................................. 107
7.3 : Interrupt Handling ................................................ 108
8 : The Compiler .......................................................... 109
8.1 : Structure of the Compiler ......................................... 111
8.2 : Invoking the Compiler ............................................. 111
8.3 : Compiler Options .................................................. 114
8.4 : A Note on Coding for Efficiency ................................... 116
8.4.1 : Avoiding Creation of Backtrack Points ........................ 116
8.4.2 : Minimizing Data Movement Between Registers ................... 120
8.5 : Assembly .......................................................... 121
9 : Modules ............................................................... 122
10 : Macros ............................................................... 126
10.1 : Defining Macros .................................................. 127
10.2 : Macro Expander Options ........................................... 129
11 : Extension Tables ..................................................... 129
12 : Other Library Utilities .............................................. 138
13 : Pragma Files ......................................................... 141
Appendix 1: Evaluable Predicates of SB-Prolog ................................ 54
Appendix 2: Adding Builtins to SB-Prolog ..................................... 58