4

標準の入力から読み取り、読み取られたすべての行のリストを作成していると仮定します。最後に、これらの行をコンマで区切って表示する必要があります。

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 ).

このコードの問題は、append呼び出しにprocessInput/3O(n)のコストがかかることです。どうすればこのコストを回避し、述語を末尾再帰にすることができますか(標準入力から多くの行を読み取る可能性があるため)?

を次のように置き換えることができると思いましたappend

LinesSoFar1 = [ Line | LinesSoFar ],

そして、それを表示する前にリストを逆にすることができます。しかし、それはハッキーのようです。もっと良い方法はありますか?

4

2 に答える 2

8

私はあなたが提案する解決策(リスト要素を前に付け、最後にリストを逆にする)を「ハッキー」とは考えていません。明示的な差分リストを使用したgusbroのソリューションもOKです。最も洗練された方法は、DCG表記(差分リストへの暗黙のインターフェイス)を使用することです。つまり、行のリストを記述するDCGを使用します。

read_lines -->
        { read_line_to_codes(current_input, Codes) },
        (   { Codes == end_of_file } -> []
        ;   { atom_codes(Line, Codes) },
            [Line],
            read_lines
        ).

使用法:phrase(read_lines, Lines)

于 2011-06-08T17:42:49.403 に答える
2

半インスタンス化された構造を使用してそれを行うことができます。このコードを確認してください:

append_init(Marker-Marker).

append_end(L-[I|NMarker], I, L-NMarker).

append_finish(L-[], L).

まず、 append_init(L)を呼び出して、半インスタンス化された構造を「初期化」します。次に、append_end(L、Item、NewList)を呼び出して、リストの最後に要素を追加できます。要素の追加が終了したら、append_finish(L、List)を呼び出して、完全にインスタンス化された最終的なリストを取得します。

例:

example(NL):-
  append_init(L), 
  append_end(L, a, L1), 
  append_end(L1, b, L2), 
  append_end(L2, c, L3), 
  append_finish(L3, NL).

?- example(L).
L = [a, b, c].
于 2011-06-08T14:30:43.170 に答える