0

最初の結果が次のようになった後に関数が停止しない理由がわかりません。

getNo(A, [[A,X]|_], X).
getNo(A, [_|Tail], X):- 
    getNo(A, Tail, X), !.
getNo(_,[],0).

入力例:

?- getNo(a,[[a,2],[b,1]],X).
X = 2 ;
X = 0.

?- getNo(b,[[a,2],[b,1]],X).
X = 1.

?- getNo(c,[[a,2],[b,1]],X).
X = 0.

ピリオドは、要素が配列の最初ではない場合に機能します。しかし、配列の最初の要素で停止しないのはなぜですか。入力例の「a」に対して 2 つの回答が返されるのはなぜですか。

それを引き起こすのは最後の行だと思いますが、そこにピリオドを置くことはできません "!." または、これを解決する他の方法を思い付くことができません。

何を変更する必要がありますか?

4

1 に答える 1

2

わかりやすくするために、感嘆符は切り取り演算子であり、「ピリオド」として動作しませ。実行されるまで、行われた選択にコミットするだけです。追跡することで、あなたが抱えている問題とは実際には関係がないことがわかります:

?- getNo(a,[[a,2],[b,1]],X).
X = 2 ; [trace]
   Redo: (6) getNo(a, [[a, 2], [b, 1]], _G221) ? creep
   Call: (7) getNo(a, [[b, 1]], _G221) ? creep
   Call: (8) getNo(a, [], _G221) ? creep
   Exit: (8) getNo(a, [], 0) ? creep
   Exit: (7) getNo(a, [[b, 1]], 0) ? creep
   Exit: (6) getNo(a, [[a, 2], [b, 1]], 0) ? creep
X = 0.

getNo(a, [], 0)ですから、これも成功することがわかります。そして、それを止めるものは何もないので、それはそれ自身でも行います:

?- getNo(a,[],X).
X = 0.

再帰呼び出しによって空のリストに到達した場合と、カットを使用するだけの直接呼び出しによって空のリストに到達した場合を区別できると期待する理由はありません。必要な動作を得るには、述語を再構築する必要があると思います。例えば:

get_number(A, [[A,X]|_], X).
get_number(A, [_|Tail],  X)  :- get_number(A, Tail, X).

getNo(A, L, X) :- get_number(A, L, X), !.
getNo(_, _, 0).

Prolog の使用に関する括弧書きとして、別の述語を作成する必要がある場合がよくあります。ヘルパー述語を作成することを恐れないでください。特に、初期条件の設定や後処理が必要なループを実際に処理する方法は他にありません。他の言語では、実行する必要があるすべての作業を単一の関数のインターフェイスの背後で完全に隔離できますが、Prolog ではそれが不可能なことが多く、ヘルパーに委譲する必要があります。

于 2013-04-22T22:47:24.867 に答える