SWI-Prolog谓词用于从输入文件中读取行

Emm*_*tOT 4 file-io prolog swi-prolog

我正在尝试编写一个谓词来接受输入文件中的一行.每次使用它时,它应该给出下一行,直到它到达文件的末尾,此时它应该返回false.像这样的东西:

database :-
    see('blah.txt'),
    loop,
    seen.

loop :-
    accept_line(Line),
    write('I found a line.\n'),
    loop.

accept_line([Char | Rest]) :-
    get0(Char),
    C =\= "\n", 
    !,
    accept_line(Rest).
accept_line([]).
Run Code Online (Sandbox Code Playgroud)

显然这不起作用.它适用于输入文件的第一行,然后无休止地循环.我可以看到我需要在某处找到一些像"C =\= -1"这样的行来检查文件的结尾,但我看不到它的去向.

所以输入和输出的示例可能是......

INPUT
this is
an example

OUTPUT
I found a line.
I found a line.
Run Code Online (Sandbox Code Playgroud)

或者我这样做完全错了?也许有一个内置规则可以做到这一点?

mat*_*mat 5

在SWI-Prolog中,最优雅的方法是首先使用DCG来描述"线"的含义,然后使用library(pio)DCG应用于文件.

这样做的一个重要优点是,您可以轻松地在顶层查询上应用相同的 DCG phrase/2,而不需要创建文件来测试谓词.

有一个DCG教程可以解释这种方法,您可以轻松地根据您的使用情况进行调整.

例如:

:- use_module(library(pio)).

:- set_prolog_flag(double_quotes, codes).

lines --> call(eos), !.
lines --> line, { writeln('I found a line.') }, lines.

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

eos([], []).
Run Code Online (Sandbox Code Playgroud)

用法示例:

?- phrase_from_file(lines, 'blah.txt').
I found a line.
I found a line.
true.
Run Code Online (Sandbox Code Playgroud)

示例用法,使用相同的DCG直接从字符代码解析而不使用文件:

?- phrase(lines, "test1\ntest2").
I found a line.
I found a line.
true.
Run Code Online (Sandbox Code Playgroud)

这种方法可以非常容易地扩展,以解析更复杂的文件内容.