我一直在阅读GNU Prolog文档,以了解如何读取一行输入,直到到达end_of_file
原子。以下是我编写这样一个目标的伪代码:
read_until_end(Chars, Out):
if peek_char unifies with end_of_file, Out = Chars
otherwise, get the current character, add it to a buffer, and keep reading
我是这样实现的:
read_until_end(Chars, Out) :-
peek_char(end_of_file) -> Out = Chars;
peek_char(C) -> read_until_end([C | Chars], Out).
prompt(Line) :-
write('> '),
read_until_end([], Line).
以下是REPL中发生的情况:
| ?- prompt(Line).
> test
Fatal Error: global stack overflow (size: 32768 Kb, reached: 32765 Kb, environment variable used: GLOBALSZ)
如果我为read_until_end
的第二个分支打印出C
,我可以看到peek_char
总是给我相同的字符'b'
。我认为我需要一种方法来处理某种类型的输入字符索引或类似的东西,但我在文档中找不到这样做的方法。如果我知道一种方法,我可能不得不使用递归来处理这样的指针,因为我不能有任何可变的状态,但除此之外,我不知道该怎么办。有人有什么建议吗?
您使用peek_char/1
来获取下一个字符,但该谓词不使用流中的字符(它只是"窥视"流(。因此,代码中会发生无限递归,最终会出现全局堆栈溢出。
您应该使用get_char/1
读取并使用流中的字符,并使用reverse/2
收集的字符列表:
read_until_end(Chars, Out) :-
get_char(Char),
(
Char = end_of_file -> reverse(Chars, Out)
;
read_until_end([Char | Chars], Out)
).
为了避免反转列表的需要,您可以稍微修改程序以按顺序构建列表(不使用累加器(:
read_until_end(Output) :-
get_char(Char),
(
Char = end_of_file -> Output=[]
;
(
Output=[Char|NOutput],
read_until_end(NOutput)
)
).
prompt(Line) :-
write('> '),
read_until_end(Line).