0

我一直在阅读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)

C如果我为 的第二个分支打印出来read_until_end,我可以看到它peek_char总是给我相同的字符,'b'。我认为我需要一种方法来推进某种类型的输入字符索引或类似的东西,但我在文档中找不到这样做的方法。如果我知道一种方法,我可能不得不使用递归来处理这样的指针,因为我不能有任何可变状态,但除此之外,我不知道该怎么做。有人有建议吗?

4

1 回答 1

3

您正在使用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).
于 2020-12-22T04:05:23.853 回答