让我们假设我们正在读取标准输入并构建已读取的所有行的列表.最后,我们需要显示那些以逗号分隔的行.
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)
我们可以在显示之前反转列表.但这看起来很糟糕.有没有更好的办法?
我不认为你提出的解决方案(在列表元素之前,然后在最后反转列表)"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)
.