§8.0 | Introduction: C-Prolog | §8.3.1 | Character I/O | |
§8.1 | Loading Programs | §8.3.2 | Term I/O | |
§8.2 | Database Manipulation | §8.3.3 | I/O Problems | |
§8.3 | File Handling | §8.4 | Term Handling |
Throughout this chapter, we use the notation of C-Prolog (as on the SUN's)
The basics we met in the initial practicals
prolog
?- spouse(Who, paul).
;
?- halt.
When preparing files for use in Prolog, remember the syntactic definition of a term
- which means the last Prolog clause must be followed by at least one space or blank line.
Thereafter,
?- consult(file_name).
|
% Which adds all the clauses therein.
|
?- reconsult(file_name).
| |
% Which replaces all the previously
|
?- [file_1, file_2, ..., file_n].
|
?- [- file_1, - file_2, ..., - file_n].
|
reconsult(file_1), reconsult(file_2), ..., reconsult(file_n).
|
~paul
to /home/s3/paul
?- system("Unix command string").
We can add files of rules - how about a single rule?
assert(clause)
always succeeds
?- assert(
| ||||
(
| ||||
happy(X):-
| ||||
free(X),
| ||||
has_coffee(X)
| ||||
)
| ||||
).
|
asserta/1, assertz/1 are procedurally-driven variants, adding procedures respectively at the start and the end of the list of rules.
The opposite of the assert family is retract/1.
Between them, "assert" and "retract" allow the database to change as the program is run ...
... but not, of course, the associated, consulted files!
To obtain a summary of the database, use
?- listing.
but note how numbers (reflecting a memory map) replace the variable names.
clause/2 works similarly for a single procedure, by matching the head and instantiating the body.
Hint: printing to a file (see §8.3 below) the output of "listing" can be useful for future runs!
A related effect
is obtained from trace/0.
Prolog manipulates sequential files of text
The notion is that of streams of data
By default, the usual rules hold
Files are opened as a side effect:
for reading | for writing | |
---|---|---|
?- see(file_name).
| ?- tell(file_name).
|
and eventually closed as another side-effect:
?- seen.
| ?- told.
|
see/1 and tell/1 both
seen/0 and told/0 both also
Thus, assuming write/1 and nl/0 both defined below, consider the following program fragments:
tell(file_1),
| )
| |
write('hello'),
| ) As on left
| |
nl,
| )
| |
told,
| ||
tell(file_2),
| )
| |
write('something'),
| )
| |
tell(file_1),
| ) As on left
| |
write('goodbye'),
| )
| |
told.
| )
|
For file_2 (which remains, potentially, open for writing) the output is
something
| something
|
But for file_1 (now closed) the output is
hello
|
| |
goodbye
|
Character handling is primitive - working through decimal ASCII values.
Output is straight-forward
put(X)
where X is an ASCII value
?- put(65), put(66), put(67).
thus gives the output ABC
Input is more complex
get0(X)
[get zero] instantiates X to the ASCII code of the next character waiting to be taken from the input stream
get(X)
is a more subtle variant, of similar behaviour except that get0(X)
| % sets X, 0 < X < 128 |
get(X)
| % skips to X, 32 < X < 128 |
If we wish, we can convert between literals and ASCII using the built in
?- name(Atom, List).
(true if List is a list of the ASCII codes for the successive characters of Atom), which is useful in term manipulation.
To input terms
we have read(X)
To output terms, we have write(X)
There are at least two other output elements
tab(Number)
nl
Let's look at a simple example, using 'read' and 'write' to improve on the crude-
square(N, N_square):-
| |
N_square is N*N.
| |
% 'is' instantiates N_square to N^2.
|
Which gives a response like:
?- square(2, X).
|
X = 4.
|
?- square (3, X).
|
X = 9
|
If we split the process into two, one to read, and one to respond:
square:-
| |
write('Number: '),
| |
read(N),
| |
process(N).
| |
process(end).
| |
% Arbitrary atom to stop with.
| |
process(N):-
| |
N_square is N*N,
| |
nl,
| |
write('Square: '),
| |
write(N_square),
| |
nl,
| |
square.
|
then the response is much neater than it was for the first version:
?- square.
|
Number: 2.
|
Square: 4
|
Number: 3.
|
Square: 9
|
Number: end.
|
yes
|
There is a catch!
For example, read(X)
Input/Output activity is essentially deterministic
Simplest equality test is X = Y
For numerical evaluation, X is Expression
Related to this is Exp_1 =:= Exp_2
Exp_1 =\= Exp_2
When we want to test the literal equality of two terms, we use Term_1 == Term_2
Term_1\== Term_2
Term_1 == Term_2
is true when both terms have the same structure and have corresponding arguments
Thus
?- f(a, b) == f(a, b).
|
yes
|
?- f(a, b) == f(a, X).
|
no
|
?- X = b, f(a, b) == f(a, X).
|
X = b
|
Somewhat related to this are the triple of
functor(Term, F, N).
arg(Number, Term, A)).
name(Atom, Ascii_list).
Moving even further towards procedural considerations, sometimes we need a guard
X is Y + Z
Prolog offers the range of guards you might expect:
integer(X).
| |
atom(X).
| |
atomic(X).
| true if X is an integer or if X is an atom |
nonvar(X).
| true if X is atomic or if X is an instantiated variable |
var(X).
| true if X is an uninstantiated variable |
and, depending on the particular version of Prolog, may have others!
© Paul Goldfinch 1997 | Next Chapter | Return to 52 349 Menu |