.\" ------------------------------ sec5.1.t ------------------------------ .sh 1 "Evaluable Predicates" .pp This section describes (most of) the evaluable predicates provided by SB-Prolog. These can be divided into three classes: \fIinline\fR predicates, \fIbuiltin\fR predicates and \fIlibrary\fR predicates. .pp 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 actually making a call to the predicate. Thus, for example, relational predicates (>/2, >=/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 predicates. .(z .TS center expand tab(%) ; l l l l. =/2%=/2 >/2%/\e/2%`\e/'/2%<>/2%=:=/2%=\e=/2%is/2 \\/1%`_\|\|$savecp'/1%`_\|\|$cutto'/1%`_\|\|$builtin'/1 `_\|$call'/1%nonvar/1%var/1%fail/0 halt/0%true/0% % .TE .sp .ce Table 1: Inline Predicates of SB-Prolog .sp 2 .)z .pp Unlike inline predicates, builtin predicates are implemented by C functions in the simulator, and accessed via the inline predicate `\fI_\|\|$builtin\fR'/1. Thus, if a builtin predicate \fIfoo\fR/3 was defined as builtin number 38, there would be a definition in the system of the form .(l foo(X,Y,Z) :\- '_\|\|$builtin'(38). .)l .pp In effect, a builtin is simply a segment of code in a large case (i.e. \fIswitch\fR) 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 \fIk\fR corresponds to the \fIk\*[th.\*]\fR case in the switch statement. SB-Prolog limits the total number of builtins to 256. .pp Builtins, unlike inline predicates, can be redefined by the user. For example, the predicate \fIfoo\fR/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. .pp 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. .pp 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 are coded into the simulator in C, the latter are written in Prolog. .sh 2 "Input and Output" .pp 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 \fBuser\fR, and refer to the user's terminal. .sh 3 "File Handling" .ip \fBsee\fR(\fIF\fR\|) \fIF\fR becomes the current input stream. \fIF\fR must be instantiated to an atom at the time of the call. .(x b (B) see/1 .)x .ip \fBseeing\fR(\fIF\fR\|) \fIF\fR is unified with the name of the current input file. .ip \fBseen\fR Closes the current input stream. .(x b (B) seen .)x .ip \fBtell\fR(\fIF\fR\^) \fIF\fR becomes the current output stream. \fIF\fR must be instantiated to an atom at the time of the call. .(x b (B) tell/1 .)x .ip \fBtelling\fR(\fIF\fR\^) \fIF\fR is unified with the name of the current output file. .(x b (B) telling/1 .)x .lp \fBtold\fR .ip Closes the current output stream. .(x b (B) told/0 .)x .ip \fB$exists\fR(\fIF\fR\^) Succeeds if file \fIF\fR exists. .(x b (B) $exists/1 .)x .sh 3 "Term I/O" .ip \fBread\fR(\fIX\fR\^) The next term, delimited by a full stop (i.e. a \*(lq.\*(rq followed by a carriage-return or a space), is read from the current input stream and unified with \fIX\fP. The syntax of the term must accord with current operator declarations. If a call \fBread\fP(\fIX\fP) causes the end of the current input stream to be reached, \fIX\fP is unified with the atom \&`end\(ul\|of\(ul\|file'. Further calls to \fBread\fP for the same stream will then cause an error failure. .(x b (L) read/1 .)x .ip \fBwrite\fP(\fIX\fP) The term \fIX\fP is written to the current output stream according to operator declarations in force. .(x b (L) write/1 .)x .ip \fBdisplay\fP(\fIX\fP) .(x b (L) display/1 .)x The term \fIX\fP is displayed on the terminal in standard parenthesised prefix notation. .ip \fBwriteq\fP(\fITerm\fP) Similar to \fBwrite\fP(\fITerm\fP), but the names of atoms and functors are quoted where necessary to make the result acceptable as input to \fBread\fP. .(x b (L) writeq/1 .)x .ip \fBprint\fP(\fITerm\fP) Prints out the term \fITerm\fR onto the user's terminal. .(x b (L) print/1 .)x .ip \fBwritename\fR(\fITerm\fR\^) .(x b (B) writename/1 .)x If \fITerm\fR is an uninstantiated variable, its name, which looks a lot like an address in memory, is written out; otherwise, the principal functor of \fITerm\fR is written out. .ip \fBwriteqname\fR(\fITerm\fR) .(x b (B) writeqname/1 .)x As for \fBwritename\fR, but the names are quoted where necessary. .lp \fBprint_al\fR(\fIN\fR, \fIA\fR) .(x b (L) print_al/2 .)x .ip Prints \fIA\fR (which must be an atom or a number) left-aligned in a field of width \fIN\fR, with blanks padded to the right. If \fIA\fR's print name is longer than the field width \fIN\fR, then \fIA\fR is printed but with no right padding. .lp \fBprint_ar\fR(\fIN\fR, \fIA\fR) .(x b (L) print_ar/2 .)x .ip Prints \fIA\fR (which must be an atom or a number) right-aligned in a field of width \fIN\fR, with blanks padded to the left. If \fIA\fR's print name is longer than the field width \fIN\fR, then \fIA\fR is printed but with no left padding. .sh 3 "Character I/O" .ip \fBnl\fP A new line is started on the current output stream. .(x b (B) nl/0 .)x .ip \fBget0\fP(\fIN\fP) \fIN\fP 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). .(x b (B) get0/1 .)x .ip \fBget\fP(\fIN\fP) \fIN\fP is the ASCII code of the next non-blank printable character from the current input stream. It has the same behaviour as \fBget0\fP on end of file. .(x b (B) get/1 .)x .ip \fBput\fP(\fIN\fP) ASCII character code \fIN\fP is output to the current output stream. \fIN\fP must be an integer. .(x b (B) put/1 .)x .ip \fBtab\fP(\fIN\fP) \fIN\fP spaces are output to the current output stream. \fIN\fP must be an integer. .(x b (B) tab/1 .)x .sh 2 "Arithmetic" .pp Arithmetic is performed by evaluable predicates which take as arguments \fIarithmetic expressions\fP and \fIevaluate\fP them. An arithmetic expression is a term built from \fIevaluable functors\fP, numbers and variables. At the time of evaluation, each variable in an arithmetic expression must be bound to a number or to an arithmetic expression. Each evaluable functor stands for an arithmetic operation. .pp The evaluable functors are as follows, where \fIX\fP and \fIY\fP are arithmetic expressions. .ip \fIX\fP\ +\ \fIY\fP addition. .ip \fIX\fP\ \-\ \fIY\fP subtraction. .ip \fIX\fP\ *\ \fIY\fP multiplication. .ip \fIX\fP\ /\ \fIY\fP division.\** Amounts to integer division if both \fIX\fR and \fIY\fR are integers. .(f \** The ``integer division'' operator `//' of C-Prolog is not supported; it can be faked using \fIfloor\fR/2 if necessary. .)f .ip \fIX\fP\ mod\ \fIY\fP \fIX\fP (integer) modulo \fIY\fP. .ip \-\fIX\fP unary minus. .ip \fIX\fP\ /\e\ \fIY\fP integer bitwise conjunction. .ip \fIX\fP\ \e/\ \fIY\fP integer bitwise disjunction. .ip \fIX\fP\ <<\ \fIY\fP integer bitwise left shift of \fIX\fP by \fIY\fP places. .ip \fIX\fP\ >>\ \fIY\fP integer bitwise right shift of \fIX\fP by \fIY\fP places. .ip \e\fIX\fP integer bitwise negation. .pp 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 floating point numbers and cumulative round-off errors in floating point arithmetic, comparisons involving floating point numbers may not always give the expected results. An effort is made to minimize surprises by considering two numbers \fIx\fR and \fIy\fR (at least one of which is a float) to be unifiable if |\fIx\fR \- \fIy\fR|/\fImin\fR(|\fIx\fR|, |\fIy\fR|) to be less than 10\*[\-5\*]. The user should note, however, that this does not guarantee immunity against round-off errors. .pp The arithmetic evaluable predicates are as follows, where \fIX\fP and \fIY\fP stand for arithmetic expressions, and \fIZ\fP for some term. Note that this means that \fBis\fP only evaluates one of its arguments as an arithmetic expression (the right-hand side one), whereas all the comparison predicates evaluate both their arguments. .lp \fIZ\fP \fBis\fP \fIX\fP .(x b (I) is/2 .)x .ip Arithmetic expression \fIX\fP is evaluated and the result, is unified with \fIZ\fP. Fails if \fIX\fP is not an arithmetic expression. One point to note is that in compiled code, the current implementation of \fBis\fR/2 cannot handle compound expressions created dynamically: these have to be handled using \fBeval\fR/2. Thus, for example, the goals .(l C ..., X = Y + Z, Y = 3, Z = 2, W is X, ... .)l would fail, whereas .(l C ..., X = Y + Z, Y = 3, Z = 2, eval(X,W), ... .)l could succeed. .ip \fBeval\fR(\fIE\fR,\ \fIX\fR\^) .(x b (L) eval/2 .)x Evaluates the arithmetic expression \fIE\fR and unifies the result with the term \fIX\fR. Fails if \fIE\fR is not an arithmetic expression. The principal difference between \fBeval\fR/2 and \fBis\fR/2 is that in compiled code, \fBis\fR/2 cannot handle arithmetic expressions that are compound terms constructed at runtime, but \fBeval\fR/2 can. On the other hand, \fBis\fR/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 \fBis\fR/2 is an inline predicate, \fBeval\fR/2 is not; thus, \fBis\fR/2 cannot be redefined by the user, but \fBeval\fR/2 can. .lp \fIX\fP \fB=:=\fP \fIY\fP .(x b (I) =:=/2 .)x .ip The values of \fIX\fP and \fIY\fP are equal. If either \fIX\fR or \fIY\fR involve compound subexpressions that are created at runtime, they should first be evaluated using \fBeval\fR/2. .lp \fIX\fP \fB=\\=\fP \fIY\fP .ip .(x b (I) =\e=/2 .)x The values of \fIX\fP and \fIY\fP are not equal. If either \fIX\fR or \fIY\fR involve compound subexpressions that are created at runtime, they should first be evaluated using \fBeval\fR/2. .lp \fIX\fP\fB < \fP\fIY\fP .(x b (I) \fP\fIY\fP .(x b (I) >/2 .)x .ip The value of \fIX\fP is greater than the value of \fIY\fP. If either \fIX\fR or \fIY\fR involve compound subexpressions that are created at runtime, they should first be evaluated using \fBeval\fR/2. .lp \fIX\fP\fB =<\fP \fIY\fP .(x b (I) ==\fP \fIY\fP .(x b (I) >=/2 .)x .ip The value of \fIX\fP is greater than or equal to the value of \fIY\fP. If either \fIX\fR or \fIY\fR involve compound subexpressions that are created at runtime, they should first be evaluated using \fBeval\fR/2. .lp \fBfloor\fR(\fIX\fR, \fIY\fR\^) .(x b (B) floor/2 .)x .ip If \fIX\fR is a floating point number in the call and \fIY\fR is free, then \fIY\fR is instantiated to the largest integer whose absolute value is not greater than the absolute value of \fIX\fR; if \fIX\fR is uninstantiated in the call and \fIY\fR is an integer, then \fIX\fR is instantiated to the smallest float not less than \fIY\fR. .lp \fBfloatc\fR(\fIF\fR, \fIM\fR, \fIE\fR\^) .(x b (B) floatc/3 .)x .ip If \fIF\fR is a number while \fIM\fR and \fIE\fR are uninstantiated in the call, then \fIM\fR is instantiated to a float \fIm\fR (of magnitude less than 1), and \fIE\fR to an integer \fIn\fR, such that .(l C \fIF\fR = \fIm\fR * 2\*[\fIn\fR\*]. .)l If \fIF\fR is uninstantiated in the call while \fIM\fR is a float and \fIE\fR an integer, then \fIF\fR becomes instantiated to \fIM\fR * 2\*[\fIE\fR\*]. .lp \fBexp\fR(\fIX\fR, \fIY\fR\^) .(x b (B) exp/2 .)x .ip If \fIX\fR is instantiated to a number and \fIY\fR is uninstantiated in the call, then \fIY\fR is instantiated to \fIe\*[X\*]\fR (where \fIe\fR = 2.71828...); if \fIX\fR is uninstantiated in the call while \fIY\fR is instantiated to a positive number, then \fIX\fR is instantiated to \fIlog\*\fR(\fIY\fR\^). .lp \fBsquare\fR(\fIX\fR, \fIY\fR\^) .(x b (B) square/2 .)x .ip If \fIX\fR is instantiated to a number while \fIY\fR is uninstantiated in the call, then \fIY\fR becomes instantiated to \fIX\fR\^\*[2\*]; if \fIX\fR is uninstantiated in the call while \fIY\fR is instantiated to a positive number, then \fIX\fR becomes instantiated to the positive square root of \fIY\fR (if \fIY\fR is negative in the call, \fIX\fR becomes instantiated to 0.0). .lp \fBsin\fR(\fIX\fR, \fIY\fR\^) .(x b (B) sin/2 .)x .ip If \fIX\fR is instantiated to a number (representing an angle in radians) and \fIY\fR is uninstantiated in the call, then \fIY\fR becomes instantiated to \fIsin\fR(\fIX\fR\^) (the user should check the magnitude of \fIX\fR to make sure that the result is meaningful). If \fIY\fR is instantiated to a number between \-\(*p/2 and \(*p/2 and \fIX\fR is uninstantiated in the call, then \fIX\fR becomes instantiated to \fIsin\fR\*[\-1\*](\fIY\fR\^). .lp .\" ---------------------- end of section sec5.1.t ---------------------- .