Prologは一階述語論理をベースにしているが、実用的なプログラミングのため、述語論理の範囲外の機能も用意されている。カットや否定の組み込みはその例である。最初にカットと否定を含む典型的な定義例を掲げて置く。% 閏年の定義% 1) 西暦年が4で割り切れる年は閏年% 2) ただし、西暦年が100で割り切れる年は平年% 3) ただし、西暦年が400で割り切れる年は閏年閏年(_西暦年) :-    0 is _西暦年 mod 400,!.閏年(_西暦年) :-    0 is _西暦年 mod 4,    \+(0 is _西暦年 mod 100).1)-3)までの定義(仕様)は、判り易いとは言い難いが、Prologのコードは明解である。400で割り切れるものは、100でも4でも割り切れるから、これを最初の節で定義する。!があるので「それで確定」である。!(カット)の効果で第二節の定義が採用される可能性はなくなる。第二節で4で割り切れるものの中で、100で割り切れるものを「除外」している。\+( )は否定であるが、除外と読んだ方が判りやすい。この閏年の定義は典型的でかつ易しい例であるが、特に!の使われ方、役割、意味は遥かに多義的で複雑である。以下それを順に述べる。Prologのバックトラックは強力な機能だが、実際のプログラムでは不要なバックトラックを制限したい場合もある。"!" (カット) はバックトラックを制限するための述語である。カットが最初に実行された時には無条件で成功するが、バックトラックでカットに制御が戻ってきたとき、カットを含む述語は無条件に失敗する。つまり、1つの述語内でカット以前に制御が戻ることはない。たとえば、通常のプログラミング言語での if p then q else r の動きは、カットを使って以下のように書ける。x :- p, !, q.x :- r.一度、pが成功して、qに進んだら、qの真偽に関わらず、後にpやrが実行される可能性はなくなる。プログラマにとって、カットが重宝なのは、条件p の否定を省略できる点にもある。x :- p,q.x :- \+(p),r.pに副作用がない場合、p,!,q とした場合と同じ意味になる。最初に示した閏年の定義で見てみよう。閏年(_西暦年) :-    0 is _西暦年 mod 400,!.閏年(_西暦年) :-    0 is _西暦年 mod 4,    \+(0 is _西暦年 mod 100).x :- p,!.x :- q,\+(r).%%%%閏年(_西暦年) :-    0 is _西暦年 mod 400.閏年(_西暦年) :-    \+(0 is _西暦年 mod 400),    0 is _西暦年 mod 4,    \+(0 is _西暦年 mod 100).x :- p.x :- \+(p),q,\+(r).%%%%を挟んで上がカットを使った記述。下は、カットの使用を避けた記述である。共にx,p,q,rで抽象したパターンを描いて添えてある。カットを避けた表現は論理式として正統な記述で推奨されるものではあるが、以下のように、x :- p1,p2,q1.x :- \+((p1,p2)),p3,q2.x :- \+((p1,p2)),\+(p3),q3.次々と、条件を否定して行かなくてはならないのでは、プログラマにとって負担が大きくなる。解読も困難になって行く。カットを使った場合と比較する。x :- p1,p2,!,q1.x :- p3,!,q2.x :- q3.このように正確な条件を記述することが大きな負担となる場合、その負担を解消するためにカットが使用されることが実は多い。これも同様の例である。文字 a を繰り返し表示したい。f(0).f(N) :-    write(a),    N_1 is N - 1,    f(N_1).ここで、?- f(30).aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaとなるが、?- f(30),fail.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaのようにfにバックトラックして来ると、動作は怪しげなことになる。少なくとも多倍長整数をサポートする処理系ではNが -1,-2,-3・・・・・と無限に小さくなっていって反応しなくなる。このような現象を避けるために、普通第一節にf(0) :- !.f(N) :-    write(a),    N_1 is N - 1,    f(N_1).上記のようにカットを入れる。これで、Nが正の整数から順次減少してきて、遂に0になり第一節が一度成功したことで、仮にバックトラックを強制されたとしても、第二節に制御が下りる可能性はなくなる。ただし、この場合でも、カットなしで済ませる方法はある。f(0).f(N) :-    N > 0,    write(a),    N_1 is N - 1,    f(N_1).でよい。問題は、正しい論理を付加することによって、ここでの例では N > 0 を記述することによって、実行の制御をすることが本当に安全かということである。!を挿入する方がずっと安全ということも考えられるのである。通常のProlog処理系では、バックトラックで戻ってくる場合に備えて、それまでに実行した各ゴールの情報や値を設定した変数を、ほとんどの場合スタック上に、アトムテーブルや述語定義の情報はメモリー上のヒープ領域と呼ばれる必要になったデータ構造を切り取って使用するための管理領域に記憶している。カットを実行すると、それらスタックやヒープ領域に置かれた情報の中で、最早決して使用されることがない情報を選別して解放することが可能になることが多い。この解放可能の領域を再度利用可能とするためには、領域を整理して使用可能域を再生(ガベージコレクション)する。このような手順を経た上ではあるが、カットは一時的に使用しているメモリを削減する。プログラマが ! を挿入することで、陽にまたは暗に、処理系に対してこのメモリー解放の要求のサインを出していると考えられることもある。さらにインタプリタ/コンパイラなどに対して、処理系に備えがあればではあるが、最適化を施すことの要求となる場合もある。カットは非決定性の述語と定義されたものを決定性に転じるためにも多用される。実例を見よう。append([],L,L).append([U|X],Y,[U|Z]) :- append(X,Y,Z).appendの定義であるが、第一引数かつ第二引数に変数が来ると非決定性に働く。?- append(X,Y,[1,2]).X = [], Y = [1,2];X = [1], Y = [2];X = [1,2], Y = [];false.である。appendの第一節の本体にカットを加えると、非決定性の性質が事実上消える。append([],L,L) :- !.append([U|X],Y,[U|Z]) :- append(X,Y,Z).?- append(X,Y,[1,2]).X = [], Y = [1,2];false.元々のappendの定義を壊さず、決定性append(X,Y,Z) :- append(X,Y,Z),!.でもよい。appendを決定性に使用したい場合は、以後appendの代わりに専ら 決定性appned を使えばよい。次に、appendの第二節の末尾にカットが来る場合を考える。append([],L,L).append([U|X],Y,[U|Z]) :- append(X,Y,Z),!.このカットも非決定性を決定性に転じる場合に使われるがそう簡単な話ではない。最初にこれでは決定性述語とはならない。?- append(X,Y,[1,2]).X = [], Y = [1,2];X = [1], Y = [2];false.最初の解 X = [], Y = [1,2]; は第一節でいきなり真になってしまう。したがって、これはまだカットとは関係がない。第二解は、通常通り第三引数の先頭要素が第一引数に移動して、それで第一引数が[1|X],第二引数tがY,第三引数が[2]となって、移動した後のappendが実行され、?- append(X,Y,[2]).X = [], Y = [2]先ほどの[1|X]のXの部分に[]が来るため、X = [1], Y = [2] が取得できる。これで一旦成功することになる。成功すると、そのとたんにカットが働く。そのカットの働きで、もう第二節の本体の副目標から次の選択肢を得る指示は与えられない。?- append(X,Y,[2]). にはもう一解存在するのだが、?- append(X,Y,[2]).X = [], Y = [2]  % ここまでは使用された。X = [2], Y = []  % この解を返す指示は来ない。その解はカットの働きで、この append(X,Y,[2]) で呼び出している副目標が偽となるため、返される機会は来ない。末尾にカットが在る場合をまとめると、このカットに到達するのは、ひとつでも解が得られたときであるが、解が得られこのカットに至った場合、カット以前にある副目標によって、次の選択肢として予定されている節選択の可能性は一切なくなる。上記の表現で言い換えれば、次の解を返す指示を出せなくなる。そして、末尾にカットのある節の後にこの述語の選択節がある場合ももちろんその節が選択されることはない。説明の順序が前後したが、実行結果の否定のためには述語"\+"が用意されている。  \+(P)  はゴールPが成功したときに失敗し、失敗したとき成功する。この述語は本当の否定 "Pは偽である" ではなく "Pは証明できない" という失敗による否定で、ある種の非単調論理による推論を行う。これは以下のように定義した述語と同じ動きをする。ここで  fail  は必ず失敗する組込述語である。\+(P) :- P, !, fail.\+(_).この否定は、カットなしには定義する方法がない。論理プログラミングにおいては、「計算は、書き換えの系列として記述される」。ところがPrologにあっては、この書き換え(導出)という表現が好ましくなく場面が現出する。それはカットが導出されるような場面だ。p :- q1,q2,q3,q4.q2 :- q5,!.q2.のような副目標 p を?- p.を q2 の第一節を導出して、?- q1,q5,!,q3,q4.   % 誤りと展開して良いであろうか。これは誤りである。実際にはこのカットは働かない。カットはそれが記述された節の本体の連接の範囲の中のみで有効である。この問題を別の観点から述べると、カットの重要な性質としてそのカットを別の副目標として置換(述語の再定義)することはできないということになる。さらに実例を示そう。p(X) :- true,!,X = 1.p(X) :- X = 2.の第一節に現れるカットをcutに置き換えたとしたら、カットの働きを失う。p(X) :- true,cut,X = 1.p(X) :- X = 2.cut :- !.最も単純な置換例が上記であるが、これでは、バックトラック後に第二節の実行を妨げられない。?- p(X).X = 1;X = 2.ここで分ることは、カットは ! が書かれた「節の実行制御」としてのみ有効ということである。カットを検証する時、取るべきプログラマの視点について最後に記す。プログラマは定義された述語の各節の本体にのみ焦点を合わせる。そして、その部分に現れるカットによってバックトラックしなくなる本体のカットより前の部分と利用されることがなくなる後続する定義節の存在は視野に入れる必要があるが、導出される謂わば子タスクとしての副目標内に現れるカットは考慮の対象から完全に外す必要がある。カットが論理プログラミングをどんなに逸脱していても、その利用が不可避である以上、このカットの有効範囲の認識はPrologの基本中の基本である。