我正在使用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谓词来实现相同的行为,以将输入流从用户(控制台)更改为另一个文件,然后使用内置的视图将其关闭(返回用户)。谓词:
我在想这样的事情:
readFileSee(InputFile, TextList) :- see(InputFile),
read_from_file(TextList),
seen. %or maybe: see(user).
但是现在,与前面的工作示例不同,我没有在其上调用get0谓词的Stream变量,因此我不知道该怎么办。
有人可以帮助我解决此问题,方法是读取InputFile的内容并将其放入TextList列表中?
最佳答案
爱丁堡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 = [#, !, /].
这里的关键是您没有传递明确的流实例,而只是依靠隐式使用标准输入或输出来完成其工作的谓词。换句话说,如果您的谓词使用的是爱丁堡I / O,则任何谓词都不应具有
Stream
参数,也不应使用open/3
。编写的包装程序类似:
telling(OldStream), tell(Filename), ..., told, tell(OldStream).