Prologで言語をサクッと作るノウハウ2019
プログラミング言語をさくっと作って見る場合のノウハウ集
評価器
% a1.pl
eval(I,I) :- integer(I).
eval(E1+E2,I) :- eval(E1,I1),eval(E2,I2),I is I1+I2.
eval(E1*E2,I) :- eval(E1,I1),eval(E2,I2),I is I1*I2.
:- eval(1+2*3+4,R),writeln(R).
:- halt.
文法定義
BNF的に木文法を定義できると便利です。
ライブラリを使うのも良いですし、マクロを使うのもよいのですが、ポータビリティの観点で考えるとソースに内包できると便利です。
以下に簡単な例を示します:
% a2.pl
:- op(1200,xfx,::=),op(650,xfx,∈),op(250,yf,*).
G∈{G}. G∈(G|_). G∈(_|G1):-G∈G1. G∈G.
syntax(G,E):-G=..[O|Gs],E=..[O|Es],maplist(syntax,Gs,Es),!.
syntax(G,E):-(G::=Gs),!,G1∈Gs,syntax(G1,E),!.
syntax(i,I):-integer(I),!.
syntax(E*,Ls):-maplist(syntax(E),Ls).
t ::= int.
e ::= i | e+e | e*e.
eval(I,I) :- integer(I).
eval(E1+E2,I) :- eval(E1,I1),eval(E2,I2),I is I1+I2.
eval(E1*E2,I) :- eval(E1,I1),eval(E2,I2),I is I1*I2.
run(E,R) :- syntax(e,E),eval(E,R).
:- run(1+2*3+4,R),writeln(R).
:- halt.
ローカルモジュール
プログラムが大きくなってくるとローカルモジュールが欲しくなることがあります。
その場合はterm_expansionを使って数行でローカルモジュールを作れるので作ってしまいましょう。
% a3.pl
:- dynamic(mod/2).
term_expansion(:-mod(M,E),:-!):-assert(mod(M,E)).
term_expansion(:-end(M),:-!):-retract(mod(M,E)),maplist(M:export,E),
forall(member(P,E),user:import(M:P)).
term_expansion(P,:-!):-mod(M,_),M:assert(P).
:- op(1200,xfx,::=),op(650,xfx,∈),op(250,yf,*).
:- mod(syntax,[syntax/2]).
G∈{G}. G∈(G|_). G∈(_|G1):-G∈G1. G∈G.
syntax(G,E):-G=..[O|Gs],E=..[O|Es],maplist(syntax,Gs,Es),!.
syntax(G,E):-(G::=Gs),!,G1∈Gs,syntax(G1,E),!.
syntax(i,I):-integer(I),!.
syntax(E*,Ls):-maplist(syntax(E),Ls).
t ::= int.
e ::= i | e+e | e*e.
:- end(syntax).
:- mod(eval,[eval/2,run/2]).
eval(I,I) :- integer(I).
eval(E1+E2,I) :- eval(E1,I1),eval(E2,I2),I is I1+I2.
eval(E1*E2,I) :- eval(E1,I1),eval(E2,I2),I is I1*I2.
run(E,R) :- syntax(e,E),eval(E,R).
:- end(eval).
:- run(1+2*3+4,R),writeln(R).
:- halt.
部分型
部分型付けは意外と難しい概念のように思えます。
とりあえず、部分型付けだけでテストしてみると良いです。
クラスの部分型付け
% a4.pl
T<:T.
A<:C :- class(A<:B),B<:C.
class(a<:top).
class(b<:a).
class(c<:b).
:- c<:top.
:- c<:a.
:- halt.
関数とレコードのある部分型付け
% a5.pl
T<:T.
_<:top.
bot<:_.
(A->B)<:(C->D) :- C<:A,B<:D.
R1<:R2 :- maplist([L:T2]>>(member(L:T1,R1),T1<:T2),R2).
:- int <: top.
:- bot <: int.
:- [x:int,y:int] <: [x:int].
:- halt.