member
, we write something like member(Item, [a, b, c])
- first the predicate name, member
, then "(", then the first argument, Item
, then a comma, then the second argument, [a, b, c]
, then ")".
However, with built-in predicates like =
, <
and >
that are usually written between their arguments, as in First < Max
, we write, in Prolog as in mathematics, in infix notation. Another infix built-in "predicate" is is
, which is used in evaluating arithmetic expressions.
It is possible in Prolog to define your own infix (and postfix) operators, and modify the syntactic handling of prefix operators - see op
.
read
, end_of_file
, get
, get_byte
, getc
, flush_output
read(X)
which reads the next term in the current input stream, which means the window on your workstation unless you have done something slightly fancy with files, and unifies it with the variableX
.
end_of_file
: if there is nothing to read in the current input stream, read(X)
causes X
to be bound to the special symbolend_of_file
. Unless you are absolutely sure you have some other way of knowing when there will be no more input data to read, you should check to make sure that the term that you have read is not end_of_file
. Ways that you might be (almost) absolutely sure: the first term read might be a number indicating how many further terms are to be read.
get_byte(C)
which reads a single character from the current input stream, and binds the equivalent integer code, in the range 0 to 255. If there is no further character to read, C
is bound to –1
.
get(C)
is like get_byte(C)
, except that it reads the first non-blank character, if any, from the current input stream.
flush_output
is actually an output goal, which ensures that any output which has been requested but not yet performed, is performed right now. Output might not be completed until there is enough to make it worthwhile, or until an operation like flush_output
forces it.
Example 1: Assume that input is coming from the user's workstation window and that procedureread_a_char
is defined as:
read_a_char(C) :- write('Type: '), flush_output, get_byte(C).
Then you can do the following - note that 43 is the character code for the character+.
?- read_a_char(Ch). Type: + Ch = 43
See also atom_codes
, for conversion of a string of numeric character codes to an atom composed of the characters represented by those character codes. For example, 102, 105, 100, and 111 are the numeric codes for the letters f, i, d, and o. atom_codes can be used as follows:
?- atom_codes(A, [102, 105, 100, 111]). A = fido
Example 2: Assume that there is a file called inputdata
, which contains on its first line the termlikes(mary, pizza).
with a full stop at the end of the term.
?- see('inputdata'), read(Term), seen. Term = likes(mary, pizza)
NB: No full stop at the end of Term's binding.
dountilstop :- repeat, read(X), (X = stop, ! ; process(X), fail ).
In this case, the code reads data, a term at a time, from the current input stream. To make that input stream a file called, say, inputdata, you would invoke the code as follows:
?- see('inputdata'), dountilstop, seen.
The call to fail
is there to force backtracking. The call to repeat
is there to force the code to endlessly repeat - that is, until something terminates the backtracking. This "something" is the cut after X = stop
- if the term read is the atom stop
, the goal X = stop
succeeds, the cut is executed, and the rule terminates.
To use the schema, replace the read operation with the one you want (might be getc
or ratom
or ...), replace the call to process
with a call to a procedure that does whateveryou want to do to the data, and you're in business. Actually - you'll probably find a few other adjustments are needed, but at least you're on the right track.
See also read
, repeat
, see
, seen
, ;
(or), and fail
.
is
, evaluationis
built-in predicate is used in Prolog to force the evaluation of arithmetic expressions. If you just write something like X = 2 + 4
, the result is to bind X
to the unevaluated term 2 + 4
, not to 6
. Example:?- X = 2 + 4. X = 2+4
If instead you write X is 2 + 4
, Prolog arranges for the second argument, the arithmetic expression 2 + 4
, to be evaluated (giving the result 6
) before binding the result to X.
?- X is 2 + 4. X = 6
It is only and always the second argument that is evaluated. This can lead to some strange-looking bits of code, by mathematical standards. For example, mod
is the remainder-after-division operator, so in Prolog, to test whether a number N
is even, we write 0 is N mod 2
, rather than the usual mathematical ordering: N mod 2 = 0.
What is the difference between N = 1
and N is 1
? In final effect, nothing. However, with N is 1
, Prolog is being asked to do an extra step to work out the value of 1 (which, not surprisingly, is 1). Arguably, it is better to use N = 1
, since this does not call for an unnecessary evaluation.
The message is: useis
only when you need to evaluate an arithmetic expression.
Actually, you don't need to use is
to evaluatearithmetic expressions that are arguments to the arithmeticcomparison operators >, >=, < =<, =:= (equal), and == (not equal), all of which automatically evaluate their arguments.
Note the syntax of is
: either
<variable> is
<expression>
or
<numeric constant> is
<expression>
Thus things like X*Y is Z*W
do not work, as X*Y
is an expression, not a variable - use either
0 is X*Y - Z*Wor
X*Y =:= Z*Winstead.
A common mistake, for people used to procedural programming languages like C and Java, is to try to change the binding of a variable by using an goal like N is N + 1
. This goal will never succeed, as it requires N
to have the same value as N + 1
, which is impossible. If you find yourself wanting to do something like this, you could look at the code for factorial
in the article on tracing
for inspiration.
Another common mistake is to try a goal involving is
before the variable(s) on the right-hand side of the is
has/have been instantiated. Prolog cannot evaluate an arithmetic expression if it doesn't know the values of variables in the expression. This is why the following example fails:
?- X is Y + 1, Y = 3. ERROR: is/2: Arguments are not sufficiently instantiatedCompare this with:
?- Y = 3, X is Y + 1. Y = 3, X = 4.
[1, 2, 3]
is a list.
The empty list is written []
.
A list with just a single item, say the number 7, is written [7]
.
Frequently it is convenient to refer to a list by giving the first item, and a list consisting of the rest of the items. In this case, one writes the list as [First | Rest]
. Note that Rest
must be a list, while Head need not be.
We have expressed this here using variables, but this need not be so, for example, we could write [1, 2, 3]
as:
[1 | [2, 3]]
[1 | Rest]
, where Rest
is bound to [2, 3]
[First | [2, 3]]
, where First
is bound to 1
[First | Rest]
, where First
is bound to 1
, and Rest
is bound to [2, 3]
[1, 2 | [3]]
[1, 2, 3 | []]
You should always write your Prolog list in the most compactreasonable format. So for example, while [X | []]
is the same list as [X]
, the second version is much easier to read, so you should use it.
It is possible to have lists of lists, or lists some of whose members are themselves lists:
Lists can also be expressed using a normal term syntax, using the built-in predicate name .
- that is, a full stop or period. In this case, the empty list atom ([]
) must be used to terminate the list. However, this approach is more cumbersome, and in practice people use the [1, 2, 3]
- style syntax. Example:
?- X = .(1, .(2, .(3, []))). X = [1, 2, 3]