#はじめに
O-Prologのテストを兼ねて、PrologでPrologインタプリタを書くということをしてみました。お遊びです。本格的なものではありません。
#超手抜きバージョン
%prolog in prolog
pp :-
repeat,
nl,write(': ?- '),
read(X),
(X=halt -> abort;true),
(call(X) -> write(yes);write(no)),
fail.
LispでLispインタプリタを記述する場合、evalを使っていいのなら、それはとても容易いことです。(print (eval (read))) で済んでしまいます。同様にPrologのresolveの部分をcall/1を使っていいのなら、上記のようなコードになります。しかし、これではつまりません。
#少し手を加えて
call/1を自前で書いてみます。組込み述語は処理系のものを呼び出すことにします。predicate_property/2で判別しています。O-Prologの場合にはbuilt_inを返すようになっています。(このあたりはISO-Prologの規格でも曖昧なようで、各種処理系によってばらつきがあります)
組込述語ではないユーザー定義の述語だった場合には、その定義された節をclause/2を使って呼び出します。そしてその本体部をmy_callで実行します。
連言と選言も自前で処理することにしました。
%prolog in prolog
pp :-
repeat,
nl,write(': ?- '),
read(X),
(X=halt -> abort;true),
(my_call(X) -> write(yes);write(no)),
fail.
%builtin
my_call(X) :-
predicate_property(X,built_in),
call(X).
%user predicate
my_call(X) :-
predicate_property(X,dynamic),
clause(X,true),
write(X),
get_char(D), %discard EOL
get_char(Z),
(\+(Z = ';') -> true;fail).
%user clause
my_call(X) :-
predicate_property(X,dynamic),
clause(X,Y),
Y \= true,
my_call(Y),
write(X),
get_char(D), %discard EOL
get_char(Z),
(\+(Z = ';') -> true;fail).
%variable
my_call(X) :-
var(X),
call(X).
%conjunction
my_call((X,Y)) :-
call(X),
my_call(Y).
%disjunction
my_call((X;Y)) :-
call(X),!.
my_call((X;Y)) :-
call(Y).
#動作
ちょっと表示がおかしいところもあるますが、それっぽく動作するようにはなりました。
O-Prolog Ver 1.19(hiromi)
| ?- ['prolog.pl'].
yes
| ?- pp.
: ?- assert(human(taro)).
yes
: ?- assert(human(jiro)).
yes
: ?- human(X).
human(taro);
human(jiro);
no
: ?- assert((error(X) :- human(X))).
yes
: ?- error(jiro).
error(jiro)
yes
: ?- halt.
|
#改良、拡張
my_callの部分をいろいろ書き換えると面白いと思います。Prolog処理系の動作について興味をもっていただけたら嬉しいです。