「Prologの基本的なデータ構造」の編集履歴(バックアップ)一覧はこちら
「Prologの基本的なデータ構造」(2014/05/07 (水) 12:26:12) の最新版変更点
追加された行は緑色になります。
削除された行は赤色になります。
**Prologの基本的なデータ構造
-単位節について
Prologの基本単位は「項(term)」と呼ばれます。
項は&bold(){単純項}と&bold(){複合項}に分類されます。
さらに単純項は&bold(){定数}と&bold(){変数}があります。
-定数
定数はプログラムの実行中に値は変化せずに一定です。
定数には数とアトムがあります。
数 ・・1234など
アトム・・abc、山田、'XYZ'など
-変数
変数はプログラムの実行前に、自身の値が定まっていない項です。
プログラムの実行中に値が決まります。
(1)英大文字で始まる任意の文字列 ・・・XYZ
(2)アンダーラインで始まる任意の文字列 ・・・_山田
-複合項
複合項は項をいくつか組み合わせてできた項です。
述語(アリティ、・・).
※Prologでは引数のことをアリティを呼びます。
----
***単位節を使ってみよう(その1)
a(1).
test:- a(X),write(X).
?-test.
1
・3つのルール
上記の実行例で、[test:-・・・]の記述がありますが、これはPrologにおいて「規則」と呼ばれます。
また[?-test.]は「質問」と呼ばれ、記述した述語を実行するルールです。
Prologには「事実」「規則」「質問」の3つのルールを用いて知識を表現できます。
事実・・・a(1).
規則・・・test:- a(1).
質問・・・?-test.
----
***ユニフィケーションについて
test述語を実行した際、a(X)が実行されます。
その際、単位節[a/1(/1はアリティ数)]が実行され、X変数に[1]が代入されます。
この仕組みを、ユニフィケーションと呼びます。
----
***単位節を使ってみよう(その2)
1
a(1,2).
test:-a(X,_),write(X).
1
2
a(X,Y).
test:-a(X,Y),write(X=Y).
_10=_11
※単位節[a(X,Y)]には定数ではなく、変数が定義されてますので、
test述語を実行した際、a(X,Y).から取得した値は未定義(変数)のため
write述語で実行した結果、未定義の値が出力されます。
よって、必ずしも[_10=_11]といった値にならないことに、注意してください。
3
a(1).
a(1,2). %こちらの単位節が呼ばれる
test:-a(X,_),write(X).
1
4
a(1,2).
a(3,4).
test:-a(X,_),write(X). %a(3,4).は実行されない。
1
上記4の実行時、単位節「a/2」の中で、a(1,2)の単位節のみ実行された。
a(3,4).も表示したい場合は、どうするか?
ここで&bold(){バックトラック}というPrologの特殊な機能を使用します。
----
***バックトラックについて
バックトラックとはプログラム実行時、ある述語の別解を求めるための制御構造です。
a(1).
a(2).
?-a(X),write(X),nl. %nlは改行する述語です
1;・・・ここで[;]と打ちEnterを押し別解を求める。
2;
no
単位節[a/1]の解を質問によって求めた際、まずa(X)のXには[1]がユニフィケーションされ
X=1が解として出力されます。この際、セミコロン[;]を入力しEnterを押すと、[1]の別解を
求められ(バックトラックし)、[2]がユニフィケーションされ、X=2が出力されます。
またX=2が出力された後、もう一度バックトラックさせると、他の解は存在しないため、[no]と
表示し終了します。
別解を求めるたびに、[;]を入力するのは手間なので、自動的にバックトラックをさせる述語がPrologには存在します。
それが[&bold(){fail}]という述語です。
a(1).
a(2).
?-a(X),write(X),nl,fail.
1
2
no
これで、上記4の実行例において、a(3,4)を表示する方法が理解して頂けたかと思います。
4・(改修)
a(1,2).
a(3,4).
test:-a(X,_),write(X),nl,fail. %failでバックトラックさせる
test:-!.
1
3
yes
----
***カットオペレータについて
バックトラックを使って、a/2単位節のすべてのデータを表示する仕組みを説明しました。
しかし、プログラムの制御によってはある単位節のデータを処理した後は、その後の
データは必要なく、処理をしてほしくない場合があるかと思います。
その際に、使うPrologの述語が「!(カットオペレータ」です。
例を示します。
a(1).
a(2).
a(3).
test:- a(X),write(X),nl,fail.
という事実と規則を定義した場合、test述語を実行すると、単位節[a/1]のデータが
すべて出力されることは、先ほど学習しました。
ではa(2)を出力した後は、a(3)を出力したくない場合は、どのようにすればよいか。
以下の用にカットオペレータを使います。
a(1).
a(2):- !.
a(3).
test:- a(X),write(X),nl,fail.
では実行してみます。
?-test.
1
2
期待した出力結果が出ましたでしょうか?
バックトラックを制御する際に、カットオペレータは使用しますので、
覚えておいてください。
----
***単位節を使ってみよう(よくある間違え)
単位節で、
a('A').
b('B').
c('C').
という事実があり、それぞれの値を表示する場合は、どうすれば良いでしょうか?
よくある間違えとして、こういう実装をしてしまう場合があります。
test:-
a(X),write(X),nl,
b(X),write(X),nl,
c(X),write(X),nl.
?-test.
A
no.
上記の述語を実行してみると、Aのみが出力され、その先は実行されずfailしました。
これは何故でしょうか?
実はPrologにおいて、変数は1度しかユニフィケーションされません。
よって、a(X)でXの値が['A']にユニフィケーションされた後、b(X)が実行されますが
これは[b('A')]を実行された事と同一になります。
b('A')の単位節は存在しない(定義されていない)ため、failされたため、上記の通りの
実行結果となりました。
a,b,cのすべてのデータを表示するには下記のようになります。
test:-
a(X),write(X),nl,
b(Y),write(Y),nl, %X以外の変数
c(Z),write(Z),nl. %X、Y以外の変数
?-test.
A
B
C
yes.
これで、a,b,cのすべての単位節のデータが表示されました。
----
***まとめ
今回は以下の事を学習しました。
・Prologのデータ構造(単純項、複合項など)
・ユニフィケーション
・バックトラック
・カットオペレータ
ここはPrologを扱うにおいて、基本的なことなので身に着けておいてください。