原点を確認する

春休みに入って時間も十分あったので、色々回り道をしてしまった。講義で、雑談に入ったら元に戻らないということがよくあるが、それと同じようなことが起きそうだった。

それで、改めて、何をやろうとしていたのかを確認しようと思った。

まず、12月の記事「短文の要約のアイデア」である。この記事の要点を再掲すると次のようになる。

「私が目標とするところからして、今、芸ロボットの到達点は50%くらいだと思っている。もし、短文要約が大きな問題なく、人と同じくらいのレベルでできるようになれば、この到達点は70%くらいまでいくだろう。・・・・ではどうすれば良いのか。一つ頭に浮かんでいるのが、要約対象が含む語の主要なものが含まれている、より短い文章の用例を探すことだ。ただ、全く同じ語については、あるかもしれないが、探すのが大変すぎる。・・・・そこで、言葉をグループ化する。例えば、りんごとバナナは、果物というグループに属するので、「デザートには〇〇が出た」という文章の〇〇には、等しく使える、置き換えられる。・・・・適用可能な言葉は、ある種の階層性を持っているのである。・・・・このグループ化、階層性を表現するために、類語辞典を使うことができる。類語辞典のコード番号を用いて、日本語ウィキペディアの全文章を用例化する。」

短文要約については、役に立ちそうな研究が極端に少なく、複数文章のよう役とは違って自然言語処理の高度な実践が必要になる。

そして次に、1月の記事「prologと自然言語解析」である。要点は次のようなものである。

「wikipediaのデータも、すべて、「論理的な言い換え」、「極端に複雑なトートロジー」である。これを表現するのにふさわしい言語は、論理型の言語だと思った。そして、prologに至った。・・・・wikipediaの 本文データのほとんどを、prologの宣言とルールに変換できないかというのが、今、考えていることの中心点である。」

この二つは似ているが、道は異なっている。第一のものは、単文要約という具体的な目的に沿って、手順も、用例を捉え、それを類語によって一般的にフォーム化するというところまで、具体的になっている。一方、第二の道は、知識をどう表現するかを課題にしている。コンセプトを語るのが目的になっている。

今、wikipediaデータがprologの宣言文となっている段階なので、それはある意味、どちらに向かうこともできるベースを作っているとも言える。

どちらにしても、prologに変換されたwikipediaのデータは膨大で、おそらく、全て完成して、swiprologに組み込めたとしても、組み込み自体に1時間かかるというものになるだろう。そして、クエリにもある程度時間がかかることが考えられ、その状況でどう実用化させるのかは不透明だ。

アソシアトロン の原理

人工知能の分野では、ディープラーニングなどの階層的ニューラルネットワークが脚光を浴びている。確かに、驚くべき成果を挙げているのだから、それは当然のことである。しかし、それが人間の脳のニューラルネットワークをシミュレートしているかといえばそうではないだろう。ディープラーニングが、その基礎的パーツとして神経回路網的構造を持っていることは確かだが、人間の脳もそのようにシステマティックに階層化されたネットワーク層を積み重ねているとは到底思えない。

人間の脳は、もっと非構造的システムのはずだ。脳には、領域ごとに違った機能を果たしていることはわかっている。しかし、その領域そのものが莫大な冗長性を持ったものであり、漠然とした機能の瞬間的作用から、人間の意識を想像している感じなのである。

そのように考えていた時、アソシアトロン というものに出会った。実は、私が30年以上前、岩手大学にいた頃、今のディープラーニングにつながるニューラルネットワークを研究していた頃、すでにこのアソシアトロン というものは世に出されていた。名前は知っていたのだ。が、当時の、バックプロぱゲーションなどを実装した並列処理システム、ニューラルネットワークの勢いの中で、真剣に考えてみたいテーマではなかったから、具体的にどのように実装するなどというところまでは全く行かなかった。

しかし、今この時に、改めてその内容を捕まえてみると、とても興味深い。そうだ、人間の脳は、きっとこんな感じなのだと思わせる、単純で、それでいてニューラルネットワークらしい漠然として機能を有している気がしてきた。

改めて、その理論の中身を捉えてみた。それは以下にまとめておいた。

アソシアトロン の原理
アソシアトロン の原理

この原理説明のpdf文書を見ていただければ明らかなように、このアソシアトロン が必ずしもそのものではない情報から記憶を再現できるのは、パターンが、そのパターンの次元倍のネットワークの中に、パターン情報を分散させるからなのである。原理的なアイデアはこれに尽きると思う。

今日のコンピュータ機能の進化した状況の中で、この単純さと優れた機能は改めて見直されるべきだと思う。

wikipedia「芸人」の定義とprolog(3)リスト処理追加

先の記事の段階で無視した、prolog化した文書の中にあるリストを処理可能にした。

%%%%%%%%%%%%%%%%
% geinin3.swi
% 2019年1月26日
% リストの場合の処理を付加した
%%%%%%%%%%%%%%%%

%%% 元の文章:
% 芸人とは、なんらかの技芸や芸能の道に通じている人、
% または身に備わった技芸や芸能をもって職業とする人
% のことを指す日本特有の概念である
%%%

%%% 節(1)
search(S,node(A,B,S),A,B).
search(S,node(A,B,L),A,B) :- member(S,L). %% リストの場合の処理
search(S,node(A,B,S),A,B).
search(S, node(_, Y, _), A, B) :- search(S, Y, A, B).
search(S, node(_, _, Z), A, B) :- search(S, Z, A, B).

%%% 受動語を検索、表示(2)
passive(X) :- sentence(T),search(X, T, A, B),printnode(B),write(A),printnode(X),nl.

%%% ノードの表示(3)
printnode(N) :- atom(N),write(N).
printnode(N) :- [X|Y] = N,write(N). %% リストの場合の表示
printnode(N) :- node(X,Y,Z) = N,printnode(Y),write(X),printnode(Z).

%%% 文章データ(4)
sentence(
    node(とは,
        芸人,
        node(ところの,
            node(を,
                node(の,
                    node(または,
                        node(いる,
                            node(に,
                                node(の,
                                    node(や,
                                        node(の,
                                            なんらか,
                                            技芸
                                        ),
                                        芸能
                                    ),
                                    道
                                ),
                               [通じて,通じる]
                            ),
                            人
                        ),
                        node(とする,
                            node(て,
                                node(を,
                                    node(や,
                                        node(た,
                                            node(に,
                                                身,
                                                [備わっ,備わる]
                                            ),
                                            技芸
                                        ),
                                        芸能
                                    ),
                                    [もっ,もつ]
                                ),
                                職業
                            ),
                            人
                        ) %%%カンマいらない
                    ),
                    こと
                ),
                指す
            ),
            node(の,
                日本特有,
                概念
            )
        )
    )
).

追加したことは、(1)の二行目に、目的とする従属語がリストの場合でもtrueになるようにしたこと。swi-prologの組み込みルールのmemberを使っている。さらに、(2)の表示ルールで、項目がリストの場合も表示するように二行目を加えた。

実行例は次のようになる。

1 ?- passive(人).
なんらかの技芸や芸能の道に[通じて,通じる]いる人
true .

2 ?- passive(通じて).
なんらかの技芸や芸能の道に通じて
true .

3 ?- passive(技芸).
なんらかの技芸
true .

4 ?- passive(職業).
身に[備わっ,備わる]た技芸や芸能を[もっ,もつ]て職業
true .

5 ?- passive(もつ).
身に[備わっ,備わる]た技芸や芸能をもつ
true .

1.は、出力時のリスト処理で、リストをそのまま出力している例だ。2.は、リストの中の文字を検索し、出力している。リストの中にはもともと[通じて,通じる]という、表現型と原型が含まれていたのだが、その表現型の方を検索し、出力している。この場合は、表現型が指定されているので、リストの出力はない。3.は、末端の語を出力させただけである。4.は、二つのリストを出力した例。5.は、「または」の二つ目の山の中にある語を出力させてみた例である。

全て、問題なく、狙った通りに出力している。パチパチ!!

wikipedia「芸人」の定義とprolog(2)改良版

定義をprologの宣言文にするプロセスを書く予定だったが、少し後回しにして、前の記事の宣言文フォーマットを改訂する。

前のような構成では、「は」、「と」とか言葉をつなぐ助詞のような項目が関係子の名前として使ったが、こうすると、助詞そのものを扱うときに面倒になる。そこで、普通の二分木のように、ノードの名前を統一する。ここでは、関係子をnodeと言うように記載しよう。

日本語の文章を、完全な二分木で表現するような試みは、他にあるのだろうが、私はみていない。

二分木を構成するノードは全て次のようになっている。

node(結合子,左項,右項)

結合子は、助詞など、名詞や動詞をノリのようにつなげるものである。ノリがノードになっているのがこのシステムの最大の特徴であると言っても良い。左項や右項は、「語」か「ノード」である。

改良したプログラムの全体を以下に示しておく。

%%%%%%%%%%%%%%%%
% geinin3.swi
% 2019年1月26日
% リストの場合の処理はしていない(リスト処理バージョンは次の記事で)
%%%%%%%%%%%%%%%%

%%% 元の文章:
% 芸人とは、なんらかの技芸や芸能の道に通じている人、
% または身に備わった技芸や芸能をもって職業とする人
% のことを指す日本特有の概念である
%%%

%%% (1)節、再帰的検索
search(S,node(A,B,S),A,B).
search(S, node(_, Y, _), A, B) :- search(S, Y, A, B).
search(S, node(_, _, Z), A, B) :- search(S, Z, A, B).

%%% (2)受動語を検索、表示
passive(X) :- sentence(T),search(X, T, A, B),printnode(B),write(A),printnode(X),nl.

%%% (3)ノードの表示:再帰的処理
printnode(N) :- atom(N),write(N).
%% printnode(N) :- [X|Y] = N,write(X). %% リストの場合の表示、使っていない
printnode(N) :- node(X,Y,Z) = N,printnode(Y),write(X),printnode(Z).

%%% (4)文章データ
sentence(
    node(とは,
        芸人,
        node(ところの,
            node(を,
                node(の,
                    node(または,
                        node(いる,
                            node(に,
                                node(の,
                                    node(や,
                                        node(の,
                                            なんらか,
                                            技芸
                                        ),
                                        芸能
                                    ),
                                    道
                                ),
                               [通じて,通じる]
                            ),
                            人
                        ),
                        node(とする,
                            node(て,
                                node(を,
                                    node(や,
                                        node(た,
                                            node(に,
                                                身,
                                                [備わっ,備わる]
                                            ),
                                            技芸
                                        ),
                                        芸能
                                    ),
                                    [もっ,もつ]
                                ),
                                職業
                            ),
                            人
                        ) %%%カンマいらない
                    ),
                    こと
                ),
                指す
            ),
            node(の,
                日本特有,
                概念
            )
        )
    )
).

後半部分が、宣言に再構成された文章である。プログラムそのものの説明は後回しにして、まず、動かしてみよう。上のプログラムを geinin2.swi というテキストファイルにしたとする。

$ swipl -f geinin3.swi

で、swi-prologに読み込み、コンパイルする。以下のように、実行を試みる。

1 ?- passive(道 ).
なんらかの技芸や芸能の道
true .

2 ?- passive(人).
なんらかの技芸や芸能の道に身に
false.

3 ?- passive(概念).
日本特有の概念
true .

最初のものは、「道」にかかる言葉をフレーズとして表示している。2番目のものは、人にかかる言葉を表示させようとしているのであるが、 [通じて,通じる]にぶつかっているので、そこで表示が止まって、falseになっている。このリストの場合の処理は、次の記事(3)で対応しているので参照されたい。最後のものは、最後のフレーズから取り出してみたものだ。

まだ、完璧ではない。リストに一旦引っかかると、エラーを出してしまう面もあるようだ。それもまた、チェックしていこうと思う。

プログラムの解説をしておこう。まず(1)の部分は、基本的なルールである。その最初のものは、終端条件である。すなわち、指定された用語と、ノードの右側の項目が一致した場合は終了である。それと同時に、A,Bに当たる情報を保持するようにしている。2番目の指揮は、左側のノードへの検索であり、3番目のものは、右側のノードへの検索である。再帰的に定義されている。A,Bの語情報を維持している。

(2)は、質問の開始節である。sentence(T)は、のちに作成した二分木データをTに取り組むための関係子(?)である。sentenceは、ルートノードと考えれば良い。X,A,Bから、検索によって得られた知識を表示させている。

(3)は、再帰的に、ノードの内容を表示させて、元の文章を再現している。最初の説は、アトムの場合は、そのまま表示させるというものである。node(X,Y,Z) = N は、Nがノードであることがわかっているので、ユニフィケーションによって、X,Y,Zの値を得ているのである。

(4)は、二分木で表された文章である。二分木の作り方は他にも色々ある。これは、私が直感的に作ったものであるが、本来目指しているのは、実際のデータをcabocha等で構文解析し、JAVAのプログラムで作成しようと考えているものである。

 

wikipedia「芸人」の定義とprolog(1)

これまで説明した、prologを自然言語処理に用いる手法を少し応用することを考える。一例として、wikipediaの「芸人」という項目冒頭にある次のような文章への応用を念頭におく。

「芸人とは、なんらかの技芸や芸能の道に通じている人、または身に備わった技芸や芸能をもって職業とする人のことを指す日本特有の概念である」

これを、これまでの記事を踏まえた形で、直感的な形でprologの宣言文にする。括弧がネストしているので、タブでその関係を表現する。基本的に、すべてオペレーターをoperator、項目をpredic_x,predic_yとすると、

operator(predic_x, predic_y)

という形になっている。二分木(Binary Tree)である。

芸人のwikipedia表現したんは、prologで次のように表される。

とは(
    芸人,
    ところの(
        を(
            または(
                いる(
                    に(
                        の(
                            や(
                                の(
                                    なんらか,
                                    技芸
                                ),
                                芸能
                            ),
                            道
                        ),
                        [通じて,通じる]
                    ),
                    人
                ), 
                の(
                    と(
                        て(
                            を(
                                や(
                                    た(
                                        に(
                                            身,
                                            [備わっ,備わる]
                                        ),
                                        技芸
                                    ),
                                    芸能
                                ),
                                [もっ,もつ]
                            ),
                            職業
                        ),
                        する
                    ),
                    人
                ),
                こと
            ),
            指す
        ),
        の(
            日本特有,
            概念
        )
    )
)

かっこの対応関係が複雑で、何度も修正した。でも、最終的にprologのコンパイルに成功した。

washida:~/Project/Prolog $ swipl -f geinin.swi 
Welcome to SWI-Prolog (threaded, 64 bits, version 7.6.4)
SWI-Prolog comes with ABSOLUTELY NO WARRANTY. This is free software.
Please run ?- license. for legal details.

For online help and background, visit http://www.swi-prolog.org
For built-in help, use ?- help(Topic). or ?- apropos(Word).

エラーがないではないか!!と敢えて書きたくなるくらい何度も失敗した(笑)。結局、かっこの対応関係の問題であって、基本的なフレームに差し障りがなかったのだ(かっこの対応関係のチェックは netbeansでやった)。文章をほとんどそのまま、prolog化できるというのは、とても重要なことである。

?- listing. してみると次のように、インデントが取れた形で組み込まれている。

とは(芸人, ところの(を(または(いる(に(の(や(の(なんらか, 技芸), 芸能), 道), [通じて, 通じる]), 人), の(と(て(を(や(た(に(身, [備わっ, 備わる]), 技芸), 芸能), [もっ, もつ]), 職業), する), 人), こと), 指す), の(日本特有, 概念))).

素晴らしい(ほぼ自画自賛)。

クエリ(問い合わせ)もしてみる。「芸人とはなんですか?」

?- とは(芸人,X).

X = ところの(を(または(いる(に(の(や(の(なんらか, 技芸), 芸能), 道), [通じて, 通じる]), 人), の(と(て(を(や(た(に(..., ...), 技芸), 芸能), [もっ, もつ]), 職業), する), 人), こと), 指す), の(日本特有, 概念)).

ちゃんと答えてくる。ただし、述語をそのまま出していることと、..., ...の部分が省略されていることが気になる。述語をそのまま出していることについては、これからなんとでもなるだろう。述語を日本語に変換するシステムは難しくない気がするから。

先の宣言文に戻って、説明すべきことを付け加えておこう。あくまでもこれは、私が直感的に(日本語を使っている私の感覚での意味)変換した。(システマティックな変換については、次の記事にもちこそうと思っている。)

(1)三つのリストが加わっている。 [通じて,通じる]、[備わっ,備わる]、[もっ,もつ]の動詞については、使われている表現系の他に、原型を次に示しておいた。これについては、活用形をすべてリスト化するつもりでいる。また、直接的な形容詞や副詞なども、関連語とともになんらかの形で、リスト化する予定である。

(2)本来の文書にはない「ところの」という、英語の関係代名詞的なこのを付け加えて、整理している。その辺りが、日本語の曖昧さの無視できないところで、実際のwikipediaのテキストからprolog述語にするときに、こういう処理も必要になるのではないかと考えている。

prologは、リスト処理の強みも持っているので、名詞や動詞もなんらかの形でリスト化する、不可分の言葉をリストで処理するなどの、システマティックな使いからを考えていきたい。

構文解析をもとに、prolog化することについては、次の記事にする。

記憶に残ったprologのプログラム

なるほどと思ったprologのプログラムをメモがわりに記載しておく。

引用元は以下で、文字コードをEUCにする必要がある。(prologでネットを漁っていると、よくEUCで書かれていて、文字コードのメタ情報が入っていないサイトにぶつかる)
http://bach.istc.kobe-u.ac.jp/prolog/intro/list.html

% 翻訳器
replace([], []).
replace([X|L], [X1|L1]) :- rule(X, X1), replace(L, L1).
% データ
rule(i, '私').
rule(you, 'あなた').
rule(have, '持つ').
rule(love, '愛する').
rule(a, '一つの').
rule(pen, 'ペン').
rule(book, '本').

実行してみる。

?- replace([i,have,a,book], L).
L = ['私','持つ','一つの','本'] ? 

?- replace([i,love,you], L).
L = ['私','愛する','あなた'] ? 

変数Lで、リストを受け取る。最初の言葉に置き換えをして、残りに自分を再帰的に呼び出している。

語順とprolog

要は、前の記事の続きである。
次のような、prologファイルを作ろう。

%%%%%%%%%%%%%%%%%%%%%
% 事実の宣言
は(ニワトリ,生む).
で(庭,生む).
を(卵,生む).
は(学生,読む).
で(図書館,読む).
を(本,読む).
% ルール
は(X,で(Y,を(Z,A))) :- は(X,A),で(Y,A),を(Z,A).
は(X,を(Z,で(Y,A))) :- は(X,A),で(Y,A),を(Z,A).
で(Y,を(Z,は(X,A))) :- は(X,A),で(Y,A),を(Z,A).
で(Y,は(X,を(Z,A))) :- は(X,A),で(Y,A),を(Z,A).
を(Z,は(X,で(Y,A))) :- は(X,A),で(Y,A),を(Z,A).
を(Z,で(Y,は(X,A))) :- は(X,A),で(Y,A),を(Z,A).
%%%%%%%%%%%%%%%%%%%%

要するに、構文解析で、すべてが最終フレーズにかかっている、先の例の場合、語順をどう変えても、意味は通じるということを示しているのである。

例えば、

?- は(学生,を(本,で(図書館,読む))).
?- で(図書館,を(本,は(学生,読む))).
?- を(本,は(学生,で(図書館 ,読む))).

は、すべて「true」となる。ただし、この三つの言葉は、ほとんど同じ意味なのだが、逆に、微妙に違ってもいる。それは、表現できていない。

助詞「で」のprolog処理:構文解析

さらに、「ニワトリは、庭で卵を生む」となったらどうだろう。素直に考えれば、prologに次の宣言文を加えれば良いということになる。

は(ニワトリ,で(庭,を(卵,生む))).

例えば、これに

?- は(ニワトリ,で(X,を(卵,生む))).

と問い合わせると、

X = 庭.

と返してくる。質問は、ニワトリはどこで卵を産みますか、という趣旨である。それに「庭」と答えているわけだ。

一見もっともらしいが、ちょっと引っかかる。「を」が「で」の中に入っているのが気になる。逆でもいいのではないかということだ。

は(ニワトリ,を(卵,で(庭,生む))).

これは、構文解析の問題である。

そこで、この文章をCabochaにかけてみる。

$ cabocha -f1
ニワトリは庭で卵を生んだ
* 0 3D 0/1 -1.268576
ニワトリ	名詞,一般,*,*,*,*,ニワトリ,ニワトリ,ニワトリ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
* 1 3D 0/1 -1.268576
庭	名詞,一般,*,*,*,*,庭,ニワ,ニワ
で	助詞,格助詞,一般,*,*,*,で,デ,デ
* 2 3D 0/1 -1.268576
卵	名詞,一般,*,*,*,*,卵,タマゴ,タマゴ
を	助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
* 3 -1D 0/1 0.000000
生ん	動詞,自立,*,*,五段・マ行,連用タ接続,生む,ウン,ウン
だ	助動詞,*,*,*,特殊・タ,基本形,だ,ダ,ダ
EOS

すなわち、ニワトリ、庭、卵、のすべての名詞句が、「生んだ」という動詞句にかかっているのである。*がついた行の2番目の3Dという記号が、3番目の句、「生んだ」への係りを表している。

そうなると、宣言文が

は(ニワトリ,生む).
で(庭,生む).
を(卵,生む).

に分解されていると考えてもいいのだろう。この三つの宣言が真の時は、

?- は(ニワトリ,で(庭,を(卵,生む))).

の問い合わせには、「真」を返して欲しい。このこと自体は、prologの規則を使って記述することができる。

は(ニワトリ,で(庭,を(卵,生む))) :- は(ニワトリ,生む),で(庭,生む),を(卵,生む).

ということになる。

次のようなファイル、test2.swiを作成して、

%%%%%%%%%%%%%%%%%%%%%
% 事実の宣言
は(ニワトリ,生む).
で(庭,生む).
を(卵,生む).
% ルール
は(ニワトリ,で(庭,を(卵,生む))) :- は(ニワトリ,生む),で(庭,生む),を(卵,生む).
%%%%%%%%%%%%%%%%%%%%%

$ swirl -f test2.swi

とprologに読み込ませて、

?- は(ニワトリ,で(庭,を(卵,生む))).
true .

クエリをかけると、trueとなる。

助詞「を」のprolog処理

次に、助詞「を」を処理しよう。前と同じ「ニワトリは卵を生む」というデータの中には「を」が入っている。先には、

は(ニワトリ,産む(卵)).

と知識化したのだが、この後半が良くなかった。そこで、そこを改良して、助詞「を」をオペレータ化をすることにする。つまり、

は(ニワトリ,を(卵,生む)).

とても、文章データを基にしたprolog知識としていい線をいっている。ほとんど、文章そのものを形にした感じがある。
この知識に対して問い合わせした結果は次のようになる。

?- は(X,を(卵,Y)).
X = ニワトリ,
Y = 生む.

?- は(ニワトリ,を(Z,生む)).
Z = 卵.

前半は、「卵というのは、ニワトリが生むものである」というわけである。後半は「ニワトリが生むとしたら、それは卵である」ということになる。少し面白いのは次の問い合わせである。

?- は(ニワトリ,Z).
Z = を(卵, 生む).

ニワトリとは何かに対して、卵を生むものであるという、意味を返してきているのである。ここには、プログラム自体と、データを同じように扱うという特色が現れているのだと思う。

さらに次のようなことを考える。元々の「ニワトリは卵を生む」という情報の中には、「卵」は「生む」という動詞に結びつくのだという大切な「知識」が含まれている。これも、prolog化できそうな気がする。

そこで、

を(卵,Z)

のユニフィケーションを求めると、次のようにエラーになる。

?- を(卵,Z).
ERROR: Undefined procedure: を/2 (DWIM could not correct goal)

当然なのは当然なのだが、なんとしたものか。もちろん、を(卵, 生む).を宣言してしまえば、問題はないのだが。なんか方法はあるはずだが、今の私のprologの知識では、なんともならない。

宣言文の中にある、相対的に独立した部分知識を取り出す手続きがあればいい。(要検討)

格助詞「は」のprolog処理

先の記事で、助詞「の」の prolog処理の例を示したが、格助詞「は」の処理例は以下のようになる。

は(ニワトリ, 鳥).
生む(A, 卵) :- は(A, 鳥).

一行目は、宣言文である。すなわち「ニワトリは鳥である」。二行目は、規則となるで、「鳥は卵を生む」を表している。もう少し丁寧に文に即して言えば「卵を生むものであるためには、それが鳥であれば良い」とも言える。

この知識を利用すると、次のように質問に答えることができる。

?- 生む(ニワトリ,卵).  %一つ目の問い合わせ
true.

?- 生む(ニワトリ,Y).   % 二つ目の問い合わせ
Y = 卵.

となる。一つ目は、ニワトリは卵を生むというのは正しい、二つ目は、ニワトリが生むとしたら、それは卵だろうということを表している。

ただ、ちょっと気に入らないところがある。元々は、「ニワトリは卵を生む」という文章をprolog化したかったのだが、少し趣旨が違ってきたように思う。

は(ニワトリ,生む(卵)).

書けば上記のようになるはずだ。これだけを prologの宣言文とする。すると次のような、問い合わせに対応できる。

%(1)
?- は(X,生む(Y)). 
X = ニワトリ,
Y = 卵.
%(2)
?- は(ニワトリ,生む(Y)).
Y = 卵.
%(3)
?- は(X,生む(卵)). 
X = ニワトリ.

(1)は、現状の知識では、何かを生む何者とは、という問い合わせに、ニワトリならば卵を生むけれどね、という答えしか出さない。(2)ニワトリが何かを生むとしたら、それは卵であると答える。(3)卵を生むものであるならば、それはニワトリであろう、というわけである。

知識が増えたらどうなるだろう。「アヒルも卵を生む」というわけである。宣言文が二つになる。

% 知識の表現
は(ニワトリ,生む(卵)).
は(アヒル,生む(卵)).

すると、先の答えが少し違ってくる。

?- は(ニワトリ,生む(卵)).
true.

?- は(アヒル,生む(卵)).
true.

?- は(X,生む(卵)).
X = ニワトリ ;
X = アヒル.

卵を生むものには、ニワトリもいるがアヒルもいる、というわけである。前者の場合は、

% 知識の表現
は(ニワトリ, 鳥).
は(アヒル, 鳥).
生む(A, 卵) :- は(A, 鳥).

となる。増えた分は単純だ。問い合わせの例は次のようになる

?- 生む(X,卵).
X = ニワトリ ;
X = アヒル.

となる。こっちの方が、単純に思える。ただ、単純な文章が持つ「知識」が、単純に表現されていないから、しっくりいかないのである。