はじめに
溝口文雄先生の本にある例題のDoctorとノーヴィッグ先生の本にあるELIZAの説明資料をもとにPrologでELIZAを作ってみました。
ELIZAとは
1960年代にワイゼンバウム教授が研究したものです。コンピューターが人間と会話をするのですが、コンピューターは構文解析、意味抽出をしているわけではありません。単にキーワードを拾ってきているだけです。ワイゼンバイム教授は人間が引きおこす錯覚に関心があったのではないかと思います。ノーヴィッグ先生の本で紹介されている教授の論文からの引用を引用します。
説明するということは、説明して疑問を解くことだと言われている。この格言は、コンピュータープログラミングの分野、とりわけヒューリスティックプログラミングや人工知能と呼ばれる分野ほどうまく当てはまる分野はない。これらの領域における機械は、驚くべき振る舞いをするので、最も経験を積んだ観察者でさえ幻惑される。しかし、プログラムの詳細が明かされ、理解を促すのに十分平易な言葉で内部の動きが説明されると、単なる理解の及ぶ手続きの集まりであることが明らかになり、魔法による幻惑から解き放たれる。我に返った観察者は「これならば書けた」と自分に言い聞かせる。彼はその考えに基づいて、問題のプログラムを保管する書架番号を「知能」から「骨董品」へと変更し、自分よりレベルの低い人たちとの議論に備えるのだ。
この論文の目的は「説明されること」に関して、以上のようなプログラムの再評価をもたらすことである。今までに、このようなことを必要としたプログラムは少ない。
実行例
| ?-eliza.
Hi!,I am Eliza
Please talk about you
|:hello there.
How do you do. Please state your problem.
|:i want to test this program.
What would it mean if you got to test this program .
|:i could see if it works.
Do you really think its likely that it works .
|:no not really.
Why not?.
|:no.
You are being a bit negative.
|:forget it-- i was wondering how general the program is.
Were you really?
|:i felt like it.
What other feelings do you have like it ?
|:i feel this is enough.
Do you often feel this is enough ?
|:bye.
See you again.
Good bye !
|
会話の仕組み
基本的な骨組みは溝口先生の本のDoctorから拝借しています。ユーザーからの入力はreader述語によりリストに変換されます。prog述語はその入力されたリストをrule述語によりパターンにあてはめて、該当する返答を書きだしています。
より人間との会話らしくするため、1つのパターンに4~5通りの返答があります。memory述語に記憶しておいて、順番に違う返答を返しています。
ruleの記述が多いですが、基本的な仕組みはとても簡単です。
本格的には
人間の会話中に my ... とあって、それをELIZAが引用する場合には your ...となった方が自然です。do not は don't と同じ意味だということもELIZAに教えてあげる必要があるでしょう。そうした詳しいことはノーヴィグ先生の本が参考になると思います。
参考文献
「Prologとその応用2」 溝口文雄監修 溝口文雄、武田正之、畝見達夫、溝口理一郎 著 総研出版
「実用Common Lisp AIプログラミングのケーススタディ」 ピーター・ノーヴィグ 著 杉本宣男 訳 翔泳社
コード
/* Eliza system */
memory(other,1).
memory(computer,1).
memory(sorry,1).
memory(iremember,1).
memory(iwant,1).
memory(if,1).
memory(no,1).
memory(yes,1).
memory(iwas,1).
eliza :-
write('Hi!,I am Eliza'),
nl,tab(3),write('Please talk about you'),
nl,prog.
prog :-
reader(X),!,rule(X),prog.
reader(X) :- nl,input(X),nl.
rule([hello|L]) :-
write('How do you do. Please state your problem.').
%computer
rule(X) :-
member(computer,X),
memory(computer,1),
retract(memory(computer,1)),
assert(memory(computer,2)),
write('Do computers worry you?').
rule(X) :-
member(computer,X),
memory(computer,2),
retract(memory(computer,2)),
assert(memory(computer,3)),
write('What do you think about machines?').
rule(X) :-
member(computer,X),
memory(computer,3),
retract(memory(computer,3)),
assert(memory(computer,4)),
write('Why do you mention computers?').
rule(X) :-
member(computer,X),
memory(computer,4),
retract(memory(computer,4)),
assert(memory(computer,1)),
write('What do you think machines have to do with your problem?').
%name
rule(X) :-
member(name,X),
write('I am not interested in names').
%sorry
rule(X) :-
member(sorry,X),
memory(sorry,1),
retract(memory(sorry,1)),
assert(memory(sorry,2)),
write('Please dont apologize.').
rule(X) :-
member(sorry,X),
memory(sorry,2),
retract(memory(sorry,2)),
assert(memory(sorry,3)),
write('Apologies are not necessary').
rule(X) :-
member(sorry,X),
memory(sorry,3),
retract(memory(sorry,3)),
assert(memory(sorry,4)),
write('What feelings do you have when you apologize?').
%I remember
rule([i,remember|L]) :-
memory(iremember,1),
retract(memory(iremember,1)),
assert(memory(iremember,2)),
write('Do you often think of'),
tab(1),printer(L),write('?').
rule([i,remember|L]) :-
memory(iremember,2),
retract(memory(iremember,2)),
assert(memory(iremember,1)),
write('Does thinking of'),
tab(1),printer(L),write('bring anything else to mind?').
%I want ...
rule([i,want|L]) :-
memory(iwant,1),
retract(memory(iwant,1)),
assert(memory(iwant,2)),
write('What would it mean if you got'),
tab(1),printer(L),write('.').
rule([i,want|L]) :-
memory(want,2),
retract(memory(iwant,2)),
assert(memory(iwant,3)),
write('Why do you want'),
tab(1),printer(L),write('.').
rule([i,want|L]) :-
memory(want,3),
retract(memory(iwant,3)),
assert(memory(iwant,1)),
write('Suppose you got'),
tab(1),printer(L),tab(1),write('soon.').
%if ...
rule([if|L]) :-
memory(if,1),
retract(memory(if,1)),
assert(memory(if,2)),
write('Do you really think its likely that'),
tab(1),printer(L),write('.').
rule([if|L]) :-
memory(if,2),
retract(memory(if,2)),
assert(memory(if,3)),
write('Do you wish that'),
tab(1),printer(L),write('.').
rule([if|L]) :-
memory(if,3),
retract(memory(if,3)),
assert(memory(if,4)),
write('What do you think about'),
tab(1),printer(L),write('.').
rule([if|L]) :-
memory(if,4),
retract(memory(if,4)),
assert(memory(if,1)),
write('Really-- if'),
tab(1),printer(L),write('.').
%no
rule(X) :-
member(no,X),
memory(no,1),
retract(memory(no,1)),
assert(memory(no,2)),
write('Why not?.').
rule(X) :-
member(no,X),
memory(no,2),
retract(memory(no,2)),
assert(memory(no,3)),
write('You are being a bit negative.').
rule(X) :-
member(no,X),
memory(no,3),
retract(memory(no,3)),
assert(memory(no,1)),
write('Are you saying "NO" just to be negative?').
rule(X) :-
member(no,X),
memory(no,3),
retract(memory(no,3)),
assert(memory(no,1)),
write('Are you saying "NO" just to be negative?').
%yes
rule(X) :-
member(yes,X),
memory(yes,1),
retract(memory(yes,1)),
assert(memory(yes,2)),
write('You seem quite positive').
rule(X) :-
member(yes,X),
memory(yes,2),
retract(memory(yes,2)),
assert(memory(yes,3)),
write('You are sure').
rule(X) :-
member(yes,X),
memory(yes,3),
retract(memory(yes,3)),
assert(memory(yes,1)),
write('I understand').
%I was ...
rule([i,was|L]) :-
memory(iwas,1),
retract(memory(iwas,1)),
assert(memory(iwas,2)),
write('Were you really?').
rule([i,was|L]) :-
memory(iwas,2),
retract(memory(iwas,2)),
assert(memory(iwas,3)),
write('Perhaps I already know you were'),
tab(1),printer(L),write('.').
rule([i,was|L]) :-
memory(iwas,3),
retract(memory(iwas,3)),
assert(memory(iwas,1)),
write('Why do you tell me you were'),
tab(1),printer(L),tab(1),write('now?').
%I feel ...
rule([i,feel|L]) :-
write('Do you often feel'),
tab(1),printer(L),write('?').
%I felt ...
rule([i,felt|L]) :-
write('What other feelings do you have'),
tab(1),printer(L),write('?').
%bye (it means stopping of conversation)
rule([bye]) :-
write('See you again.'),
nl,write('Good bye !'),nl,abort.
%other
rule([]) :-
memory(other,1),
retract(memory(other,1)),
assert(memory(other,2)),
write('Very interesting.').
rule([]) :-
memory(other,2),
retract(memory(other,2)),
assert(memory(other,3)),
write('I am not sure I understand you fully.').
rule([]) :-
memory(other,3),
retract(memory(other,3)),
assert(memory(other,4)),
write('What does that suggest to you?').
rule([]) :-
memory(other,4),
retract(memory(other,4)),
assert(memory(other,5)),
write('Please continue').
rule([]) :-
memory(other,5),
retract(memory(other,5)),
assert(memory(other,6)),
write('Go on').
rule([]) :-
memory(other,6),
retract(memory(other,6)),
assert(memory(other,1)),
write('Do you feel strongly about discussing such things?').
rule([_|L]) :-
rule(L).
printer([]).
printer([X|Y]) :- write(X),tab(1),printer(Y).
input(X) :- in(X,[],[]).
in(X,Y,Z) :- get0(C),test(C,X,Y,Z).
test(31,X,Y,Z) :- in(X,[],[]). %Unit Separator
test(32,X,Y,[]) :- in(X,Y,[]). %Space
test(32,X,Y,Z) :- name(X1,Z),append(Y,[X1],Y1),in(X,Y1,[]).
test(46,X,Y,[]). %Period
test(46,X,Y,Z) :- name(X1,Z),append(Y,[X1],X).
test(C,X,Y,Z) :- append(Z,[C],X1),in(X,Y,X1).