避免在Prolog中追加/ 3的线性成本

Ash*_*ley 3 prolog dcg

让我们假设我们正在读取标准输入并构建已读取的所有行的列表.最后,我们需要显示那些以逗号分隔的行.

go:-
    prompt(_, ''),
    processInput([ ], Lines),
    findall(_, (member(L, Lines), write(L), write(',')), _),
    nl.

processInput(LinesSoFar, Lines):-
    read_line_to_codes(current_input, Codes),
    processInput(Codes, LinesSoFar, Lines).

processInput(Codes, LinesSoFar, Lines):-
    ( Codes \= end_of_file
    ->
        atom_codes(Line, Codes),
        append(LinesSoFar, [ Line ], LinesSoFar1),  % <---- append/3 - O(n)
        processInput(LinesSoFar1, Lines)
    ;
        Lines = LinesSoFar ).
Run Code Online (Sandbox Code Playgroud)

这个代码的问题在于append调用processInput/3成本为O(n).我们怎样才能避免这种成本并且仍然让我们的谓词是尾递归的(因为我们可能从标准输入中读取了很多行)?

在我看来,我们可以用append以下内容代替.

LinesSoFar1 = [ Line | LinesSoFar ],
Run Code Online (Sandbox Code Playgroud)

我们可以在显示之前反转列表.但这看起来很糟糕.有没有更好的办法?

mat*_*mat 7

我不认为你提出的解决方案(在列表元素之前,然后在最后反转列表)"hacky".具有显式差异列表的gusbro解决方案也是可以的.我认为最优雅的方法是使用DCG表示法(差异列表的隐式接口),即使用描述行列表的DCG:

read_lines -->
        { read_line_to_codes(current_input, Codes) },
        (   { Codes == end_of_file } -> []
        ;   { atom_codes(Line, Codes) },
            [Line],
            read_lines
        ).
Run Code Online (Sandbox Code Playgroud)

用法:phrase(read_lines, Lines).