みずからが持っている知識にもとづき、問いに答えるシステムのプリミティブなものを作った。持っている知識は次のような「アトムはロボットです」という知識だけであるとする。現実には、日本語wikipediaの膨大な知識を持っているのだが、それを利用するのはもう少し後にする。
知識は、knowledgeというfanctorで表現されているとする。%で始まる行は、prologのコメント文である。
%% 知識 = アトムはロボットです %% phrases: [ r0 1 ] knowledge(testline_0_0, node(は, [アトム, 'S:普/C:自然物/D:科学・技術'], node(です, [ロボット, 'S:普/C:人工物-その他/D:科学・技術'], [ ] ) ) ).
ここで、「アトムとはなんですか」という問いがあったとする。それに回答するprologプログラムは次のようなものである。
% % 質問に答えるプログラム % :- ['../lib/client.swi']. :- ['../lib/wsprint.swi']. :- create_client(localhost,25000). reply(Sentence,Out) :- chat_to_server('GETTREE',Sentence,Recv), %% write(Recv),nl, %% utf8string.swiから出てくる文字列は、string!! %% このままでは、unificationに失敗するので、termに変換する term_string(Recv1,Recv), dialog(_,Tree) = Recv1, %% write(Tree),nl, isquestion(Tree), getsubject(Tree,Sub), getreply(Sub,Out), wsprint(Out). %% ----- 疑問文 回答取得 ----- getreply(Subject,Out) :- knowledge(_,Tree),chkreply(Tree,Subject),Out=Tree. %% 主語のフレーズが一致していたらそれを回答とみなす chkreply(node(N,L,_),Subject) :- member(N,[は, とは, って]),L=Subject,!. chkreply(node(_,L,_),Subject) :- chkreply(L,Subject),!. chkreply(node(_,_,R),Subject) :- chkreply(R,Subject). %% ----- 疑問文 主語取得 ----- getsubject(node(N,L,_),Out) :- member(N,[は, とは, って]),L=Out,!. getsubject(node(_,L,_),Out) :- getsubject(L,Out),!. getsubject(node(_,_,R),Out) :- getsubject(R,Out). %% ----- 疑問文 チェック ----- %% ノード値がリストのいずれかの語で、右の葉が空リスト [ ] の場合、疑問文 isquestion(node(N,_,[])) :- member(N,[ですか,なの,か,なのか]),!. isquestion(node(_,L,_)) :- isquestion(L),!. isquestion(node(_,_,R)) :- isquestion(R). %% 知識 = アトムはロボットです %% phrases: [ r0 1 ] knowledge(testline_0_0, node(は, [アトム, 'S:普/C:自然物/D:科学・技術'], node(です, [ロボット, 'S:普/C:人工物-その他/D:科学・技術'], [ ] ) ) ).
プログラムの最後に、先ほどの知識が加えられている。もしこの知識が多く、あるいは、複雑になれば、それらを調べることになる。
reply()が、topレベルのclauseである。質問文(Sentence)は、平文であり、それらはサーバーに問い合わせして二分木にして返してもらっている(chat_to_server('GETTREE',Sentence,Recv),)。サーバーから返ってきた二分木は、swi-prologのstringであり、このまま dialog(_,Tree) = Recv, などとunificationすると失敗する。この理由がわからなくて、半日くらい無駄にした。term_string(Recv1,Recv),で、stringを文字列に変換している。返ってきたものから、二分木だけを取り出し(dialog(_,Tree) = Recv1,)、質問文であるかどうかをチェックし(isquestion(Tree),)、質問文であるならば、質問の主語にあたるものを取り出し、知識に問い合わせして、回答に当たる知識を得る(getreply(Sub,Out),)、という段取りである。
実行結果は次のようになる。
?- ['reply.swi']. true. ?- reply(アトムとはなんですか,Out). アトムはロボットです/ Out = node(は, [アトム, 'S:普/C:自然物/D:科学・技術'], node(です, [ロボット, 'S:普/C:人工物-その他/D:科学・技術'], [])) .