PrologによるPrologインタプリタ


はじめに

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処理系の動作について興味をもっていただけたら嬉しいです。