how to read a file in prolog?

2019-07-15 19:33发布

问题:

I want to read a text file like test.txt:

birthbook(tom,9,1).
birthbook(add,9,1).
birthbook(ddd,8,1).

Code:

test:-
  open('test.txt', read, Str),
  read_file(Str,Lines),
  close(Str),
  write(Lines), nl.

read_file(Stream,[]) :-
  at_end_of_stream(Stream).
read_file(Stream,[X|L]) :-
  \+ at_end_of_stream(Stream),
  read(Stream,X),
  read_file(Stream,L).

However, it shows that ERROR: test.txt:1:4: Syntax error: Unexpected end of file.

回答1:

as an example of controlling Prolog peculiar execution flow, consider how to turn read/2, a non backtrackable builtin, into one suitable for findall/3:

read_one_term(S, B) :-
    repeat,
    read(S, B),
    ( B = end_of_file, !, fail ; true ).

?- open('book.pl', read, S), findall(B, read_one_term(S, B), L), close(S).
S = <stream>(0x7f51b00b3340),
L = [birthbook(tom, 9, 1), birthbook(add, 9, 1), birthbook(ddd, 8, 1)].


回答2:

There are a couple of issues I see with your implementation. First, the at_end_of_stream/1 succeeds only after an attempt was already made to read past the last line in the file. It does not tell you whether you are about to read past the end. So your predicate is going to do the stream read after the last line is read, instantiating X with end_of_file before at_end_of_stream/1 succeeds. (This is similar to the behavior of the feof(.) function in the standard C library, which the veteran C programmers will tell you to avoid using.)

The second issue is you don't take care of the case when at_end_of_stream/1 does succeed.

You can refactor your code as follows:

read_file(Stream, Lines) :-
    read(Stream, Line),               % Attempt a read Line from the stream
    (  at_end_of_stream(Stream)       % If we're at the end of the stream then...
    -> Lines = []                     % ...lines read is empty
    ;  Lines = [Line|NewLines],       % Otherwise, Lines is Line followed by
       read_file(Stream, NewLines)    %   a read of the rest of the file
    ).

A quick test yields:

?- open('test.txt', read, Str), read_file(Str, Lines), close(Str), write(Lines), nl.
Str = <stream>(0x871c410),
Lines = [birthbook(tom, 9, 1), birthbook(add, 9, 1), birthbook(ddd, 8, 1)].

?-


标签: prolog