LoginSignup
0

More than 5 years have passed since last update.

Prologで言語をサクッと作るノウハウ2019

Posted at

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.

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0