次の事実と述語を考えると:
_sound(time1).
sound(time2).
Sun(time3).
relax(X):-sound(X),!,Sun(X).
relax(_):-Sun(_).
_
relax(S).
を実行すると、_S=time1
_が原因で_!
_を取得することが期待されます。つまり、(間違っている場合は修正してください)、「X」が満たされている場合は、バックトラックを停止します。
トレースは次のとおりです。
_3 ?- trace.
true.
[trace] 3 ?- relax(S).
Call: (6) relax(_G1831) ? creep
Call: (7) sound(_G1831) ? creep
Exit: (7) sound(time1) ? creep
Call: (7) Sun(time1) ? creep
Fail: (7) Sun(time1) ? creep
Fail: (6) relax(_G1831) ? creep
false.
_
では、なぜPrologはSun(time1)
に満足した後、感嘆符を満たしたにもかかわらず、sound(X)
もチェックするのですか(sound(time1)
は事実であるため)。
_!
_記号は、右側の句が左側に戻るのを防ぎます。これは一方向のゲートのようなもので、カットを超えて戻ることはありません。
sound(time1)
がtrueの場合、次の句Sun(time1)
が評価され、プロローグはSun(time1)
がfalse
であることを検出します(ナレッジベースを検索することにより、実際にはそれが事実であることを知っているわけではありません)。
次に、カットのため、プロローグは最初の節の値_time2
_および_time3
_を試行しません。
カットの詳細:
Prologは、述語の節を左から右に評価します。左端の句の変数に値をバインドします。句がtrue
の場合、次の句に移動します。 false
の場合、prologは他の値も試行します。
いずれかの句がどの値でも満たすことができない場合、それはfalse
になり、述語全体になります(句がANDで結合されているため)。
全体がツリーの深さ優先走査として機能します。ここで、句はノードであり、エッジはその変数のさまざまな値を表します。トラバーサルが句をfalse
であると検出した場合、前の句に戻り、別の値を試します。
これがカットです。 2つの句の間にカット(_!
_)を置くと、afterの句がfalse
になり、新しい値を試すことを意味しますカット後に評価が実行された場合にのみ続行されます。これは、カットの前に使用された変数の値がlockedであり、評価がカットを超えたときに変更できないことを意味します。
これをさらに明確にするために、誰かが感嘆符演算子の動作にまだ苦労している場合(私がしたように)、ここに例があります:
_sound(time3).
sound(time1).
Sun(time1).
relax(X):-sound(X),!,Sun(X).
_
この特定の例では、Prologに?-relax(S).
を要求すると、結果はfalseになります。 Prologは次のように機能していると説明できます。
私が4で言ったように反対に!演算子それは結果として成功。
_sound(time3).
sound(time1).
Sun(time1).
relax(X):-sound(X),Sun(X).
_
ある時点で私が間違っている場合は、遠慮なく訂正してください。
それでもルールの残りの部分を満たそうとしますが、感嘆符の前に戻ることはありません。つまり、Sun(X)
が失敗した場合、バックトレースせずにdifferentオブジェクトをsound(X)
に一致させようとしますが、そのルールに完全には一致しません。