2

我正在使用 SWI Prolog 研究 Prolog,我发现关于如何从文件中读取文本数据并使用see内置谓词将其打印在屏幕上的许多困难。

我有这个程序,它使用读取模式中的打开谓词和与该文件关联的流来读取文件的内容

readFile(InputFile, TextList):- open(InputFile, read, Stream),
                                readCharacter(Stream, TextList),
                                close(Stream),
                                !.

readCharacter(Stream,[]):- at_end_of_stream(Stream).    %condizione di uscita


readCharacter(Stream,[Char|Rest]):-
                                 get0(Stream,Char),
                                 readCharacter(Stream,Rest).

这很简单,但我问我是否可以使用see谓词来实现相同的行为,以将输入流用户(控制台)更改为另一个文件,然后使用内置的 see 关闭此流(返回给用户)谓词:

我在想这样的事情:

readFileSee(InputFile, TextList) :- see(InputFile),
                                    read_from_file(TextList),
                                    seen. %or maybe: see(user).

但是现在,与前面的工作示例不同,我没有调用get0谓词的Stream变量,所以我不知道怎么回事。

有人可以帮我解决这个问题,读取 InputFile 的内容并将此内容放入 TextList 列表中吗?

4

2 回答 2

3

Edinburgh I/O 很方便,但有点小故障,因为它的工作原理是搞乱全局状态。这个想法是使用不带流参数的读写谓词。你假装你正在从标准输入读取或写入标准输出。然后,在调用以这种方式工作的代码之前,将全局输入或输出流更改为要读取或写入的文件。

因此,假设您要读取三个原子字符。你可能会写:

read_three([A,B,C]) :- get_char(A), get_char(B), get_char(C).

这适用于标准输入:

?- read_three(X).
|: abc

X = [a, b, c].

为了让它与文件一起工作,你用一个 包装它seeing(OldStream), see(filename), ..., seen, see(OldStream),你的代码在该...部分中。例如,我们可以这样做:

read_three(Filename, Three) :- 
    % the wrapper to switch files
    seeing(OldStream), see(Filename), 

    % your code
    read_three(Three), 

    % the wrapper to switch back
    seen, see(OldStream).

使用它,你需要有一个文件名来读取,但它可能看起来像这样:

?- read_three('clone.sh', X).
X = [#, !, /].

这里的关键是你没有传递一个显式的流实例,你只是依赖于隐式使用标准输入或输出的谓词来完成他们的工作。换句话说,如果您的谓词Stream使用 Edinburgh I/O,则它们都不应该有参数,您也不应该使用open/3.

编写的包装器是类似的:telling(OldStream), tell(Filename), ..., told, tell(OldStream).

于 2013-04-18T16:51:20.400 回答
2

考虑library(pio)改用:用 DCG 描述文件内容,然后将phrase_from_file/2其应用于文件。

于 2013-04-18T14:56:19.740 回答