Question

I'd like to read a plain text file and apply a predicate to each line (the predicates contain write which does the output). How would I do that?

Was it helpful?

Solution

In SWI-Prolog, the cleanest solution is to write a DCG that describes what a "line" is, then call a predicate for each line. Use library(pio) to apply the DCG to a file.

EDIT: As requested, consider:

:- use_module(library(pio)).

lines([])           --> call(eos), !.
lines([Line|Lines]) --> line(Line), lines(Lines).

eos([], []).

line([])     --> ( "\n" ; call(eos) ), !.
line([L|Ls]) --> [L], line(Ls).

Sample usage: ?- phrase_from_file(lines(Ls), 'your_file.txt').

OTHER TIPS

You can use read to read the stream. Remember to invoke at_end_of_stream to ensure no syntax errors.

Example:

readFile.pl

main :-
    open('myFile.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).

myFile.txt

'line 0'.
'line 1'.
'line 2'.
'line 3'.
'line 4'.
'line 5'.
'line 6'.
'line 7'.
'line 8'.
'line 9'.

Thus by invoking main you will recieve the output:

?- main.
[line 0,line 1,line 2,line 3,line 4,line 5,line 6,line 7,line 8,line 9]
true 

Just configure main. The output here is an example by using write, of course. Configure to match your request.

I assume that this principle can be applied to answer your question. Good luck.

There are kind of more possible in number and more reasonable in performance solutions, to get uninterpreted i.e plain text lines from a file:

SWI-Prolog:

read_line(S, X) :- 
   read_line_to_codes(S, L), 
   read_line2(L, X).

read_line2(end_of_file, _) :- !, fail.
read_line2(L, X) :-
   atom_codes(X, L).

Jekejeke Prolog:

:- use_module(library(stream/console)).

Here are some timings, reading a file of 655 lines:

test :-
   open('<path>', read, Stream),
   test(Stream),
   close(Stream).

test(Stream) :-
   read_line(Stream, _), !,
   test(Stream).
test(_).

SWI-Prolog:

̀?- time((between(1,100,_), test, fail; true)).
% 328,300 inferences, 0.125 CPU in 0.143 seconds (88% CPU, 2626400 Lips)
true.

Jekejeke Prolog:

?- time((between(1,100,_), test, fail; true)).
% Up 121 ms, GC 2 ms, Thread Cpu 94 ms (Current 05/07/19 17:19:05)
Yes

I guess a SWI-Prolog solution that reads into a string instead into an atom could be faster. But in the above we compare atom against atom reading.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top