#Prologのカットの使い方
大学の講義でprologをやっているのですがカット「!」について最初悩んで苦悶したので備忘録として投稿しようと思いました.
##カットの基本的な使い方
以下のルールに従ったprologプログラムをカットを使う場合とカットを使わない場合で
ルール1:X<2ならY=0
ルール2:2 $\leq$ XかつX<4ならY=2
ルール3:4 $\leq$ XならY=4
カットを使わない場合
f(X,0) :- X<2.
f(X,2) :- 2=<X,X<4.
f(X,4) :- 4=<X.
カットを使う場合
f(X,0) :- X<2,!.
f(X,2) :- 2=<X,X<4,!.
f(X,4) :- 4=<X.
カットを使わないex1の方では例えばf(1,Y)という目標を実行したときにYは0に具体化され後の文は実行しなくともfailすることは確定ですがPrologの性質上のバックトラックによって後の2文も実行されます.
カットを使うex2の方ではf(1,Y)という目標を実行したときにYは0に具体化されバックトラックをせずに文末のピリオドで終わります
カットは一度バックトラック制御と多くの教科書に書いてありますが,私の個人的な考えではカットの前までの節がfalseな場合のみ「!」以降の文を行うと考えた方がいいと思いました.
##カットの応用的な使い方
これは講義で問題として出された問題を使用したいと思います
fを項のファイルとする.
findallterm(Term)
が,f中の項でTermとマッチする全てのものを端末に表示するように
手続きfindalltermを定義せよ.
Termがその過程で値の具体化を受けないようにせよ
findallterm(Term):-
read(Term0),process(Term0,Term).
process(end_of_file,_):- !.
process(Term0,Term):-
(not(Term0=Term),!;
write(Term0),nl),
findallterm(Term).
###プログラムex3の使い方
see('読み込むファイル名'),findeallterm(探したい単語),seen.
###説明
read,writeに関しては組み込み述語であるので説明しません
ここではファイルの中にfindalltermに渡す引数が存在しているかどうかを調べます.
ここで重要なのが
(not(Term0=Term),!;
write(Term0),nl),
findallterm(Term).
のところでnot(Term0=Term)がtrueであればfindallterm(Term)が行われ,falseであれば「;」によってもう一度process(Term0,Term)を行い今度は前項を行わずwrite(Term0),nlの項を実行されます.
別の問題を仮定して,検索したい文字がファイルに存在した場合にfalseを返し、それ以外はファイルの文字を出力するプログラムを作ってみます.ex3の抽出したex4の部分を下記のプログラムに入れ替えることでできます
(not(Term0=Term),!,write(Term0),nl),
findallterm(Term).
これはnot(Term0=Term)がtrueであればカット以降の分を行いfalseであればfindallterm(Term)を行うというプログラムが出来上がります.
この使い方をすればprologの中でまるで他言語で言うif文が使えるようになります