Yes

advertisement
Part 1 The Prolog Language
Chapter 6
Input and Output
1
6.1 Communication with files


The method of communication between the user and the
program:
 User questions to the program
 Program answers in terms of instantiations of variables
Extensions to this basic communication method are
needed in the following areas:
 input of data in forms other than questions—for
example, in the form of English sentences,
 output of information in any format desired, and
 input from and output to any computer file or device
and not just the user terminal.
2
6.1 Communication with files

We first consider the question of directing input and
output to files.
 The program can read data from several input files
(input streams), and output data to several output
files (output streams).
 Data coming from the user’s terminal is treated as just
another input stream.
 Data output to the terminal is treated as another
output stream.
User
terminal
user
Input
streams
user
file 1
file 2
file 3
file 4
Output
streams
3
6.1 Communication with files





At any time during the execution of a Prolog program,
only two files are ‘active’:
 one for input (current input stream)
 one for output (current output stream)
The current input stream can be changed to another file,
Filename, by the goal:
see( Filename)
The current output stream can be changed by a goal of the form:
tell( Filename)
The goal seen closes the current input file.
 seen closes the current input, and resets it to user input.
The goal told closes the current output file.
 told closes the current output, and resets it to user output.
4
6.1 Communication with files

For examples:
…
see( file1),
read_from_file( Information),
see( user),
…
tell( file3),
write_on_file( Information),
tell( user),
…

Another example:
readfile( X, Y) :- see('test.txt'), get( X), get( Y), seen.
writefile(X) :- tell('test1.txt'), put( X), told.
| ?- readfile(X, Y).
X = 48
Y = 49
test.txt
yes
0123456 …
| ?- writefile(99).
yes
test1.txt
c
5
Exercises

Please write a program to open two text files: testa.txt
and testb.txt, and read data from them alternately.
| ?- readfile(X, Y).
X = 52
Y = 56
Y from testb.txt
yes
X from testa.txt

Please write a program to open one text file: testc.txt,
and write two data.
| ?- writefile(65, 66).
6
6.2 Processing files of terms
6.2.1 Read and write

read( X):


The built-in predicate read is used for reading terms from the
current input stream.
The goal read( X) will cause the next term, T, to be read, and
this term will be matched with X.

If X is a variable then X will become instantiated to T.

If matching does not succeed then the goal read( X) fails.


The predicate read is deterministic, so in the case of failure
there will be no backtracking to input another term.
If read( X) is executed when the end of the current input file
has been reached then X will become instantiated to the atom
end_of_file.
readfile( X, Y) :- see('test.txt'), read( X), read( Y), seen.
7
6.2 Processing files of terms
6.2.1 Read and write

write( X):





The built-in predicate write outputs a term.
The goal write( X) will output the term X on the current
output file.
X will be output in the same standard syntactic form in which
Prolog normally displays values of variables.
A useful feature of Prolog is that the write procedure ‘knows’
to display any term no matter how complicated it may be.
For example:
| ?- write("this is a test").
[116,104,105,115,32,105,115,32,97,32,116,101,115,116]
| ?- write('this is a test').
this is a test
yes
8
Examples
| ?- read(X), write(X).
'This is a test'.
This is a test
X = 'This is a test'
yes
| ?- read(X), write(X).
"This is a test".
[84,104,105,115,32,105,115,32,97,32,116,101,115,116]
X = [84,104,105,115,32,105,115,32,97,32,116,101,115,116]
yes
| ?- get(X), put(X).
c
c
X = 99
yes
9
6.2 Processing files of terms
6.2.1 Read and write

An example:
cube( N, C) :C is N * N * N.
| ?- cube(2, X).
X=8
yes
| ?- cube(5, Y).
Y = 125
yes
| ?- cube(12, Z).
Z = 1728
yes
cube :read( X), process( X).
process( stop) :- !.
process( N) :C is N * N * N, write( C), cube.
| ?- cube.
2.
8
5.
125
12.
1728
stop.
(16 ms) yes
10
Exercise
cube :- read( stop), !.
cube :- read( N), C is N * N * N, write( C), cube.
Is the above procedure correct? Why? Would you
please show some correct examples?
11
6.2 Processing files of terms
6.2.1 Read and write

An incorrect simplified:
cube :- read( stop), !.
cube :- read( N), C is N * N * N, write( C), cube.




The reason why this is wrong can be seen easily if we
trace the program with input data 5.
The goal read( stop) will fail when the number is read,
and this number will be lost forever.
The next read goal will input the next term.
On the other hand, it could happen that the stop
signal is read by the goal read( N), which would then
cause a request to multiply non-numeric data.
12
6.2 Processing files of terms
6.2.1 Read and write

tab( N):




The built-in predicates for formatting the output.
They insert spaces and new lines into the output
stream.
The goal tab( N) causes N space to be output.
The predicate nl (which has no arguments) causes the
start of a new line at output.
cube :- read( X), process( X).
process( stop) :- !.
process( N) :- C is N * N * N,
tab(10), write( C), nl, cube.
13
6.2 Processing files of terms
6.2.1 Read and write

Another version:
cube :- write(‘Next item, please: ’),
read( X), process( X).
process( stop) :- !.
process( N) :C is N * N * N,
write(‘Cube of ’), write( N),
write(‘ is ’), write( C), nl, cube.
| ?- cube.
Next item, please: 5.
Cube of 5 is 125
Next item, please: 12.
Cube of 12 is 1728
Next item, please: stop.
(31 ms) yes
14
6.2 Processing files of terms
6.2.2 Displaying lists

writelist( L):

The procedure outputs a list L so the each elements of
L is written on a separate line:
writelist([]).
writelist([X|L]) :- write( X), nl, writelist( L).
| ?- writelist( [a, b, c]).
a
b
c
yes
15
6.2 Processing files of terms
6.2.2 Displaying lists

writelist2( L):

If we have a list of lists, we can define the procedure:
writelist2([]).
writelist2([L|LL]) :- doline( L), nl, writelist2( LL).
doline([]).
doline([X|L]) :- write( X), tab(1), doline( L).
| ?- writelist2([[a,b,c],[d,e,f],[g,h,i]]).
abc
def
ghi
(15 ms) yes
16
6.2 Processing files of terms
6.2.2 Displaying lists

bars( L):


A list of integer numbers can be sometimes
conveniently shown as a bar graph.
The procedure, bars, can be defined as:
bars([]).
bars([N|L]) :- stars( N), nl, bars( L).
stars( N) :- N > 0, write( *), N1 is N-1, stars(N1).
stars( N) :- N =<0.
| ?- bars([3,4,6,5]).
***
****
******
*****
true ?
yes
17
Exercise

Please write a procedure square(N) to draw a
square with size N. For example,
| ?- square(3).
***
***
***
yes
18
Exercise

Please write a procedure square which can read two
parameters N and S and draw a NXN square with symbol
S. For example,
| ?- square.
Please input square size N: 4.
Please input symbol S: &
&&&&
&&&&
&&&&
&&&&
yes
19
Exercise

Please write a procedure squares which can read two
parameters N and S and draw NXN squares with symbol S. This
procedure will exit if the value of N is 0. For example,
| ?- square.
Please input
Please input
GGG
GGG
GGG
Please input
Please input
88888
88888
88888
88888
88888
Please input
yes
square size N: 3.
symbol S: G
square size N: 5.
symbol S: 8
square size N: 0.
20
6.2 Processing files of terms
6.2.3 Processing a file of terms

processfile:


A typical sequence of goals to process a whole file, F,
would look something like this:
…, see( F), processfile, see( user), …
Here processfile is a procedure to read and process
each term in F, one after another, until the end of the
file is encountered.
processfile :- read( Term), process( Term).
process( end_of_file) :- !.
process( Term) :- treat( Term), processfile.

Here treat( Term) represents whatever is to be done
with each term.
21
6.2 Processing files of terms
6.2.3 Processing a file of terms

An example:

This procedure showfile can display on the terminal
each term together with its consecutive number.
showfile( N) :- read( Term), show( Term, N).
show( end_of_file, _) :- !.
show( Term, N) :- write(N), tab( 2), write( Term), nl,
N1 is N+ 1, showfile( N1).
| ?- showfile(3).
a.
3 a
aa.
4 aa
abcdefg.
5 abcdefg
test.
6 test
22
Exercises


Let f be a file of terms. Define a procedure
findterm( Term)
that displays on the terminal the first term in f that matches Term.
Let f be a file of terms. Write a procedure
findallterms( Term)
That displays on the terminal all the terms in f that match Term.
Make sure that Term is not instantiated in the process (which could
prevent its match with terms that occur latter in the file).
23
Exercise

Let testfile.txt be a file. Write a procedure
printfile( ‘testfile.txt’)
that displays on the terminal all the context in testfile.txt.
printfile(FILE) :- see(FILE), process, seen.
process :- read(Term), test(Term).
test(end_of_file) :- !.
test(Term) :- write(Term), write('.'), nl, process.
processfile(FILE) :- see(FILE), process, seen.
process :- get_char(Term), test(Term).
test(end_of_file) :- !.
test(Term):- write(Term), process.
processfile(FILE) :- see(FILE), process, seen.
process :- get_char(Term), test(Term).
test(end_of_file) :- !.
test(Term):- write(Term), process.
24
6.3 Manipulating characters

A character is written on the current output stream with the goal
put( C)

where C is the ASCII code (0-127) of the character to be output.
For example:
?- put( 65), put( 66), put( 67).
would cause the following output
ABC
 65 is the ASCII code of ‘A’, 66 of ‘B’, 67 of ‘C’.

A single character can be read from the current input stream by
the goal
get0( C)

get0( C) causes the current character to be read from the input

stream.
The variable C becomes instantiated to the ASCII code of this
character.
get( C)

get( C) is used to read non-blank characters.

get( C) causes the skipping over of all non-printable characters.
25
6.3 Manipulating characters

Define procedure squeeze:


Squeeze (壓縮) can read a sentence from the current
input stream, and output the same sentence
reformatted so that multiple blanks between words are
replaced by single blanks.
For example:
An acceptable input is then:
The
robot tried to pour wine out
 The goal squeeze would output:

of the
bottle.
The robot tried to pour wine out of the bottle.
squeeze :- get0( C), put( C), dorest( C).
dorest( 46) :- !.
dorest( 32) :- !, get( C), put( C), dorest( C).
dorest( Letter) :- squeeze.
26
6.3 Manipulating characters
squeeze :- get0( C), put( C), dorest( C).
dorest( 46) :- !.
dorest( 32) :- !, get( C), put( C), dorest( C).
dorest( Letter) :- squeeze.
| ?- squeeze.
this is a test.
this is a test.
(15 ms) yes
| ?- squeeze.
a full stop , a blank or a letter
a full stop , a blank or a letter .
yes
Here still has a blank, can you
improve the program to remove this?
.
Ps. The ASCII code of ‘,’ is 44.
27
Exercise



Given a squeeze procedure defined as follows:
squeeze :- get0( C), put( C), dorest( C).
dorest( 46) :- !.
dorest( 32) :- !, get( C), put( C), dorest( C).
dorest( Letter) :- squeeze.
We can run this program and show it result.
| ?- squeeze.
a full stop , a blank or a letter
.
a full stop , a blank or a letter .
yes
Here still has a blank, can you improve the program to remove
this?
For example: a full stop, a blank or a letter.
28
6.4 Constructing and decomposing
atoms

name( A, L):



name is a built-in predicate.
name is true if L is the list of ASCII codes of the
characters in A.
For example:
| ?- name( Z, [122, 120, 50, 51, 50]).
Z = zx232
yes
| ?- name( zx232, A).
A = [122,120,50,51,50]
Yes

There are two typical uses of name:
(1) given an atom, break it down into single characters.
(2) given a list of characters, combine them into an atom.
29
6.4 Constructing and decomposing
atoms

The example of first kind of application:
taxi( X)
taxi( X) tests whether an atom X represents a taxi.
taxi( X) :- name( X, Xlist), name( taxi, Tlist),
conc( Tlist, _, Xlist).
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
| ?- taxi( taxia1).
yes
| ?- taxi( taxilux).
yes
| ?- taxi( taxtax).
no
30
6.4 Constructing and decomposing
atoms
taxi( X) :- name( X, Xlist), name( taxi, Tlist),
conc( Tlist, _, Xlist).
conc([],L,L).
conc([X|L1],L2,[X|L3]) :- conc(L1,L2,L3).
| ?- taxi(taxilux).
1 1 Call: taxi(taxilux) ?
2 2 Call: name(taxilux,_104) ?
2 2 Exit: name(taxilux,[116,97,120,105,108,117,120]) ?
3 2 Call: name(taxi,_143) ?
3 2 Exit: name(taxi,[116,97,120,105]) ?
4 2 Call: conc([116,97,120,105],_138,[116,97,120,105,108,117,120]) ?
5 3 Call: conc([97,120,105],_138,[97,120,105,108,117,120]) ?
6 4 Call: conc([120,105],_138,[120,105,108,117,120]) ?
7 5 Call: conc([105],_138,[105,108,117,120]) ?
8 6 Call: conc([],_138,[108,117,120]) ?
8 6 Exit: conc([],[108,117,120],[108,117,120]) ?
7 5 Exit: conc([105],[108,117,120],[105,108,117,120]) ?
6 4 Exit: conc([120,105],[108,117,120],[120,105,108,117,120]) ?
5 3 Exit: conc([97,120,105],[108,117,120],[97,120,105,108,117,120]) ?
4 2 Exit: conc([116,97,120,105],[108,117,120],[116,97,120,105,108,117,120]) ?
1 1 Exit: taxi(taxilux) ?
yes
{trace}
31
6.4 Constructing and decomposing
atoms

Another example of second kind of application:
getsentence( Wordlist)


getsentence reads a free-form natural language
sentence and instantiates Wordlist to some internal
representation of the sentence.
For example:
 If the current input stream is:
Mary was pleased to see the robot fail.
 The goal getsentence( Wordlist) will cause the
instantiation:
Sentence = [‘Mary’, was, pleased, to, see, the,
robot, fail]
32
6.4 Constructing and decomposing
atoms
% Figure 6.2 A procedure to transform a sentence into a list
of atoms.
getsentence( Wordlist) :get0( Char), getrest( Char, Wordlist).
getrest( 46, [] ) :- !.
getrest( 32, Wordlist) :- !, getsentence( Wordlist).
getrest( Letter, [Word | Wordlist] ) :getletters( Letter, Letters, Nextchar),
name( Word, Letters),
getrest( Nextchar, Wordlist).
getletters( 46, [], 46) :- !.
getletters( 32, [], 32) :- !.
getletters( Let, [Let | Letters], Nextchar) :get0( Char), getletters( Char, Letters, Nextchar).
33
6.4 Constructing and decomposing
atoms

The procedure getsentence first reads the current input
character, Char, and then supplies this character to the
procedure getrest to complete the job.
getsentence( Wordlist) :get0( Char), getrest( Char, Wordlist).
| ?- getsentence(X).
Mary was pleased to see the robot fail.
X = ['Mary',was,pleased,to,see,the,robot,fail]
yes
| ?- getsentence(X).
test a file.
X = [test,a,file]
yes
34
6.4 Constructing and decomposing
atoms

getrest has to react properly according to three cases:
(1)
(2)
(3)
Char is the full stop: then everything has been read.
Char is the blank: ignore it, getsentence form rest of input.
Char is a letter: first read the word, Word, which begins with
Char, and the use getrest to read the rest of the sentence,
producing Wordlist. The cumulative result is the list
[Word|Wordlist].
getrest( 46, [] ) :- !.
getrest( 32, Wordlist) :- !, getsentence( Wordlist).
getrest( Letter, [Word | Wordlist] ) :getletters( Letter, Letters, Nextchar),
name( Word, Letters),
getrest( Nextchar, Wordlist).
| ?- name( t, T).
T = [116]
| ?- name( a, T).
T = [97]
| ?- getrest(116, X).
est a file.
X = [test,a,file]
yes
| ?- getrest(97, Y).
file.
Y = [a,file]
(16 ms) yes
35
6.4 Constructing and decomposing
atoms

The procedure that reads the characters of one word is:
getletters( Letter, Letters, Nextchar)
The three arguments are:
(1)
Letter is the current letter (already read) of the word being
read.
(2)
Letters is the list of letters (starting with Letter) of up to
the end of the word.
(3)
Nextchar is the input character that immediately follows
the word read.
Nextchar must be a non-letter character.
getletters( 46, [], 46) :- !.
getletters( 32, [], 32) :- !.
getletters( Let, [Let | Letters], Nextchar) :get0( Char),
getletters( Char, Letters, Nextchar).
36
6.4 Constructing and decomposing
atoms
getletters( 46, [], 46) :- !.
getletters( 32, [], 32) :- !.
getletters( Let, [Let | Letters], Nextchar) :get0( Char),
getletters( Char, Letters, Nextchar).
| ?- getletters(116, X, Y).
est.
X = [116,101,115,116]
Y = 46
yes
| ?- getletters(116, X, Y).
est
X = [116,101,115,116]
Y = 32
yes
| ?- getletters(116, X, Y).
1 1 Call: getletters(116,_42,_43) ?
2 2 Call: get0(_123) ?
e
2 2 Exit: get0(101) ?
3 2 Call: getletters(101,_85,_43) ?
4 3 Call: get0(_174) ?
s
4 3 Exit: get0(115) ?
5 3 Call: getletters(115,_136,_43) ?
6 4 Call: get0(_225) ?
t
6 4 Exit: get0(116) ?
7 4 Call: getletters(116,_187,_43) ?
8 5 Call: get0(_276) ?
.
8 5 Exit: get0(46) ?
9 5 Call: getletters(46,_238,_43) ?
9 5 Exit: getletters(46,[],46) ?
7 4 Exit: getletters(116,[116],46) ?
5 3 Exit: getletters(115,[115,116],46) ?
3 2 Exit: getletters(101,[101,115,116],46) ?
1 1 Exit: getletters(116,[116,101,115,116],46) ?
X = [116,101,115,116]
Y = 46
(78 ms) yes
37
6.4 Constructing and decomposing
atoms
| ?- getsentence(X).
test and test.
X = [test,and,test]
yes
| ?- getsentence(X).
test.
X = [test]
yes
| ?- getsentence([X]).
test.
X = test
yes
| ?- getsentence([X]).
test and test.
(16 ms) no
uncaught exception: error(syntax_error('user_input:43 (char:10) .
or operator expected after expression'),read_term/3)
38
Exercise


Define the relation
starts( Atom, Character)
to check whether Atom starts with Character.
Please update the program getsentence to process the
comma(,)(44) and semicolon(;)(59) symbols.
For example: | ?- getsentence(X).
That is a test; this is a test, too.
X = ['That', is, a, test, this, is, a, test, too]
39
6.5 Reading programs

consult( F):


We can tell Prolog to read a program from a file F.
For example:
|?- consult( program3).




All the clauses in file program3 are read and loaded into
the memory.
They will be used by Prolog when answering further
questions from the user.
If another file is ‘consulted’ at some later time during the
same session, then the clauses from this new file are
added into the memory.
However, details depend on the implementation and other
circumstances.
40
6.5 Reading programs



If the new file contains clauses about a procedure defined in the
previously consulted file, then
 the new clauses may be simply added at the end of the
current set of clauses, or
 The previous definition of this procedure may be entirely
replaced by the new one.
Several files may be consulted by the same consult goal.
 For example:
|?- consult([program3, program4, queens]).
Consulted programs are used by a Prolog interpreter.
| ?- consult('C:/GNU-Prolog/Prologcode/programs/fig1_8.pl').
compiling C:\GNU-Prolog\Prologcode\programs\fig1_8.pl for
byte code...
C:\GNU-Prolog\Prologcode\programs\fig1_8.pl compiled, 42
lines read - 2851 bytes written, 31 ms
yes
41
Download