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のプログラムで作成しようと考えているものである。