前回の提案の話を Twitter でしたところ、尾崎さん(通称Prologおじさん)に勝手にしろ。などと突き放されてしまいました。
わかったよ。勝手にするよ。このわからずや。こんな家出ていってやる。うぉー。っていうのも有りです。青春です。
しかしながら、DCG も最初から受け入れられていたわけではないでしょうし、DCGは --> 演算子を使って導入したことで、他の構文とも同居出来たように、新たな構文も同居可能なのではないでしょうか?
そのような考えから、:>
演算子を導入して :>
を使った文のみを変換するよう改良してみました。
実行例
% eval6.npl
eval(Γ,X, V) :- member(X = V, Γ).
eval(_Γ,_i,_i) :- integer(_i).
eval(_Γ,a_+_b, v) :> eval(Γ, a,_v),eval(Γ, b,_v1),v_ is v + v1.
eval(_Γ,a_*_b, v) :> eval(Γ, a,_v),eval(Γ, b,_v1),v_ is v * v1.
eval(_Γ,x_=_a;_b, v) :> eval(Γ, a,_v),eval([x = v|Γ], b,_v).
t(_Γ,_x,t) :> atom(x),member(x:t_, Γ).
t(_Γ,_i,Int) :> integer(i).
t(_Γ,a_+_b,Int) :> t(Γ,a,Int),t(Γ,b,Int).
t(_Γ,a_*_b,Int) :> t(Γ,a,Int),t(Γ,b,Int).
t(_Γ,x_=_a;_b,t) :> t(Γ,a,_t),t([x:t|Γ],b,_t).
run(_e, r, t) :> t([], e,_t), eval([], e,_r).
:> run(x = 1 * 2 + 3 * 4; x,_r,_t), writeln(r:t).
:> a_ = 1, a_ is a+1, a_ is a+1, writeln(a).
:> a_:Int = x:_t, writeln(a:t).
:- halt.
今回は最初の2行は今までどおり :-/2
の記述が可能です。
3行目以降は :>/2
を使っているので、新たな記法が使えます。
:>/1
:-/1
も使うことが出来ます。
実装
% npl3.pl
:- op(1200,fx,[:>]).
:- op(1200,xfx,[:>]).
read_file_terms(F,R) :-
open(F,read,FP),read_terms(FP,R,[]),close(FP).
read_terms(FP, Terms, Tail) :-
read_term(FP, C1, [variable_names(Vs)]),read_terms_conv(C1,Vs),
read_terms(C1, FP, Terms, Tail).
read_terms(end_of_file, _, Tail, Tail) :- !.
read_terms(C, FP, [C|T], Tail) :-
read_term(FP, C2, [variable_names(Vs)]),read_terms_conv(C2,Vs),
read_terms(C2, FP, T, Tail).
read_terms_conv((:> _),Vs) :- maplist(call,Vs).
read_terms_conv((_ :> _),Vs) :- maplist(call,Vs).
read_terms_conv(_,_).
% 述語1つを変換
conv_terms(_,[],[],I,I) :- !.
conv_terms(E,[C|Cs],[C2|Cs2],I,I2) :- conv_goal(E,C,C2,I,I1),conv_terms(E,Cs,Cs2,I1,I2).
conv_goal(_,V,V,I,I) :- var(V),!.
conv_goal(_,V,V3,I,I) :- atom(V),(concat('_',V2,V);concat(V2,'_',V)),memberchk(V2=V3,I),!.
conv_goal(_,V,V3,I,[V2=V3|I]) :- atom(V),(concat('_',V2,V);concat(V2,'_',V)).
conv_goal(E,V,V2,I,I) :- atom(V),memberchk(V=V2,E),!.
conv_goal(_,V,V,I,I) :- atomic(V),!.
conv_goal(E,V,V2,I,I2) :- V=..[C|Cs], conv_terms(E,Cs,Cs2,I,I2), V2=..[C|Cs2].
simpl(I1,I2) :- simpl([],I1,I2).
simpl(E,[],E).
simpl(E,[X=_|I1],I2) :- memberchk(X=_,E),simpl(E,I1,I2).
simpl(E,[V|I1],I2) :- simpl([V|E],I1,I2).
merge(S1,[],S1).
merge(S1,[X=V|S2],S3) :- member(X=V,S1),merge(S1,S2,S3).
merge(S1,[X=V|S2],S3) :- merge([X=V|S1],S2,S3).
conv_goals((A,B),(A1,B1)) --> conv_goals(A,A1),conv_goals(B,B1).
conv_goals((A;B),(A1;B1),I,I3) :-
conv_goal(I,A,A1,[],I1),conv_goal(I,B,B1,[],I2),
simpl(I1,S1),simpl(I2,S2),merge(S1,S2,S3),append(S3,I,I3).
conv_goals(A,A1,I,I2) :- conv_goal(I,A,A1,[],I1),append(I1,I,I2).
% 文を変換
conv_stmt((:> V),(:- V2)) :- !,conv_goals(V,V2,[],_).
conv_stmt((H :> V),(H3 :- V2)) :- !,conv_goals((H,V),(H2,V2),[],I),!,
conv_goals(H2,H3,I,_).
conv_stmt(V,V).
% 文のリストを変換
conv_stmts(Vs,Vs2) :- maplist(conv_stmt,Vs,Vs2).
assert1(:- V) :- call(V).
assert1(V) :- assertz(V).
consult1(F) :- read_file_terms(F,R),conv_stmts(R,R2),maplist(assert1,R2).
:- current_prolog_flag(argv, Argv),maplist(consult1,Argv).
:>
演算子を使った場合だけ変換するよう変更しました。
まとめ
新たな構文を既存文法に加え混在できるように修正しました。
これならば従来のPrologの資産を生かしつつ新規ユーザーは新しい構文で記述することが出来ます。
今までの資産を切り捨てることなく新しい構文を利用できます。