I want to open a text file, read (arbitrary) lines from it, and construct program state from the extracted information. In particular, I am wanting to track the line numbers as the file is processed. I've written the code below, but my experience with prolog is limited and I'd appreciate any comments or suggestions that the community has.
I've looked at similar questions on stack overflow and the web, and found the detailed answer from Daniel Lyons (https://stackoverflow.com/a/16096728/11542361) very helpful, but it doesn't track the line numbers. I've also looked at Anne Ogborn's tutorial (Using Definite Clause Grammars in SWI-Prolog; referenced from https://stackoverflow.com/a/14015035/11542361) but the text that I'm looking to process is largely unstructured (with no clear grammar rules).
The code that I've written is:
%% Text processing framework
%
% Idea is to open a file, read lines from it, and construct
% program state. The state below just counts the number of lines
% in the input file, along with the number of lines containing
% the substring "Added" [for illustrative purposes only].
source_file('logfile.txt').
main(_Argv) :-
source_file(Source_File),
open(Source_File, read, Input),
% Sample state: count # lines containing 'Added'
load_state(Input, state(added(0),lines(0)), State, 0),
!, % prohibit backtracking to load_state()
close(Input),
print(State). % process loaded information
%% load_state(+Input, +Old_State, -New_State, +Previous_Line_Number)
load_state(Input, Old_State, New_State, Previous_Line_Number) :-
Line_Number is Previous_Line_Number + 1,
read_line_to_string(Input, Line),
load_state_x(Input, Line, Old_State, New_State, Line_Number).
% load_state_x enforces termination at end_of_file, and also
% invokes recursion back to load_state() for the next line.
load_state_x(_, end_of_file, State, State, _).
load_state_x(Input, Line, Old_State, New_State, Line_Number) :-
process_line(Line, Old_State, Next_State, Line_Number),
load_state(Input, Next_State, New_State, Line_Number).
% process_line() has knowledge of the system state, and updates it.
process_line(Line, state(added(Count),lines(_)),
state(added(New_Count),lines(Line_Number)), Line_Number) :-
sub_string(Line,_,_,_,"Added"),
New_Count is Count + 1.
% "Added" not a substring of Line (per above)
process_line(_Line, state(added(Count),lines(_)),
state(added(Count),lines(Line_Number)), Line_Number).
The code above works in SWI-Prolog (in limited testing); it has not been tried on any other prolog systems.