1

プロローグ機能を作ろうとしています。関数は文を読み取り、キーワードの抽出を試みます。キーワードが見つかった場合は、メッセージを出力します。キーワードが見つからない場合にもメッセージを出力したい。これが私の例です:

contains([word1|_]) :- write('word1 contained').
contains([Head|Tail]) :- Head \= word1, contains(Tail).
contains([word2|_]) :- write('word2 contained').
contains([Head|Tail]) :- Head \= word2, contains(Tail).
contains([word3|_]) :- write('word3 contained').
contains([Head|Tail]) :- Head \= word3, contains(Tail).

上記のコードは、抽出された単語が存在するかどうかを確認します。ただし、単語 'word1,word2 または word3' が含まれていない場合は、答えになりません。これを実装する方法を知っている人はいますか?

追加してみました:

contains([_|_]) :- write('nothing contained'),nl.
contains([Head|Tail]) :- Head \= _, contains(Tail).

しかし、これが間違っていることは明らかです。

4

4 に答える 4

4

述語を含むの主要部分を記述する標準的な方法は次のとおりです。

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail).

つまり:

  • 単語を見つけたら、それ以上検索しないでください (これがカット (!) 演算子の目的です)。
  • 他に何も機能しない場合は、末尾に再帰します。

何も見つからない場合に回答を追加するには、再帰呼び出しに別のカットを追加するだけで、後のケースは (再帰を含む) 他に何も機能しない場合にのみ呼び出されます。

contains([word1|_]) :- !, write('word1 contained').
contains([word2|_]) :- !, write('word2 contained').
contains([word3|_]) :- !, write('word3 contained').
contains([Head|Tail]) :- contains(Tail), !.
contains(_) :- write('Nothing found').
于 2009-11-23T12:22:53.053 に答える
2

命令型言語では、ある種のフラグを使用します。例えば:

found = False
for word in wordlist:
    if word in ('car', 'train', 'plane'):
        print "Found: " + word
        found = True
if not found:
    print "Nothing found."

このフラグを別のパラメーターとして句に実装できます。

% entry point
contains(X) :- contains(X, false).

% for each word...
contains([Word|Rest], Flag) :-
    Word = car   -> (write('Car found.'),   nl, contains(Rest, true)) ;
    Word = train -> (write('Train found.'), nl, contains(Rest, true)) ;
    Word = plane -> (write('Plane found.'), nl, contains(Rest, true)) ;
    contains(Rest, Flag).

% end of recursion
contains([], true).
contains([], false) :- write('Nothing found.'), nl.

単語ごとに異なる句を作成する (そしてループを抽象化する) 場合は、中間部分を次のように変更します。

% for each word...
contains([Word|Rest], Flag) :-
    checkword(Word) -> NewFlag=true ; NewFlag=Flag,
    contains(Rest, NewFlag).

% and at the end:
checkword(car)   :- write('Car found.'), nl.
checkword(plane) :- write('Plane found.'), nl.
checkword(train) :- write('Train found.'), nl.
于 2009-11-23T12:09:17.170 に答える
1

これを行う方法は次のとおりです。

contains(Words) :-
    findall(Word,has(Words,Word),Sols),
    print_result(Sols).

% Word is a target word in the list Words
has(Words,Word) :-
    member(Word,Words), 
    member(Word,[word1,word2,word3]).

print_result([]) :- write('Nothing found.\n').
print_result([X|Xs]) :- print_sols([X|Xs]).

print_sols([]).
print_sols([X|Xs]) :-
    concat(X, ' contained.\n',Output),
    write(Output),
    print_sols(Xs).

このアプローチの利点は、より高いレベルの抽象化を使用して、述語を読みやすくすることです。ターゲット単語のリストが 1 つしかないため、新しい単語ごとに個別の節を追加する必要がなく、保守も容易になります。

トリックは、2 回has使用する述語にあります。member/21 回目は入力リストから項目を選択し、2 回目はそれがターゲット単語の 1 つであることをテストします。これを引数として使用するfindall/3と、入力リストで見つかったすべてのターゲット単語が生成されます。

注: [X|Xs]inprint_resultsは、最初の句でカットを使用する必要がないようにします。

于 2009-11-23T12:50:57.280 に答える
0

liori さんがベストアンサーだと思います。以下は、場合によっては理にかなっている可能性がある、わずかに異なるアプローチです。

  • プリントアウトを生成する
  • 印刷物が空の場合は「何も見つかりませんでした」と印刷し、そうでない場合は印刷物を出力します

以下は SWI-Prolog で機能しますが、他の Prolog ではおそらく機能しませんwith_output_to/2

% Define what are the keywords
keyword(word1).
keyword(word2).
keyword(word3).

% Define how the found keywords are pretty-printed
print_keyword(W) :-
    format("Found: ~w.~n", [W]).

% Generate a print-out and output it unless its empty
print_keywords(Words) :-
    with_output_to(atom(PrintOut),
                   forall((member(W, Words), keyword(W)), print_keyword(W))),
    (
        PrintOut == ''
    ->
        writeln('Nothing found.')
    ;
        write(PrintOut)
    ).
于 2009-12-01T02:29:44.667 に答える