わかりやすくするために、感嘆符は切り取り演算子であり、「ピリオド」として動作しません。実行されるまで、行われた選択にコミットするだけです。追跡することで、あなたが抱えている問題とは実際には関係がないことがわかります:
?- 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 ではそれが不可能なことが多く、ヘルパーに委譲する必要があります。