Prologは言語実装の実験するのに最高なので四則演算のインタプリタを作ってみますよ。
モチベーション
なんか、youtubeの放送を見てて唐突にやる気が出た。面白いのだけど、低レイヤー勢にもPrologを使ってほしいと思ったんです。はい。
自作ブラウザを拡張する作業配信 - JavaScriptインタプリタをつくる #low_layer_girls
SWI-Prolog インストール
brew install swi-prolog
apt install swi-prolog
などでインストールできます。
構文:
e ::= i | e+e | e-e | e*e | e/e. % 式
v ::= i. % 値
評価規則と実行
eval.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(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 div I2.
:- eval(1+2+3+4,R),writeln(R),R=10.
:- halt.
実行してみます。
$ swipl eval.pl
10
評価規則と実行(2)
PrologのアトムはLispのシンボルみたいなもので、JavaScriptの文字列の代わりにアトムを使って足し算の規則を追加してみたいと思います。
eval.pl
eval(I,I):-integer(I),!.
eval(X,X):-atom(X),!.
eval(E1+E2,I):- eval(E1,I1),eval(E2,I2),!,
(integer(I1),integer(I2)->I is I1+I2;format(atom(I),'~w~w',[I1,I2])).
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(E1/E2,I):- eval(E1,I1),eval(E2,I2),I is I1 div I2.
:- eval('12'+34,R),writeln(R),R='1234'.
:- eval(12+34,R),writeln(R),R=46.
:- halt.
実行してみます:
$ swipl eval.pl
1234
46
できましたー。以上です。
バックトラック使ってさらに美しく
eval.pl
eval(E1+E2,I):- eval(E1,I1),eval(E2,I2),!,
(integer(I1),integer(I2)->I is I1+I2;format(atom(I),'~w~w',[I1,I2])).
の規則はバックトラックを使うと以下のように分けてかけます:
eval.pl
eval(E1+E2,I):- eval(E1,I1),eval(E2,I2),integer(I1),integer(I2),I is I1+I2.
eval(E1+E2,X):- eval(E1,V1),eval(E2,V2),format(atom(X),'~w~w',[V1,V2]).
こちらの規則の方が美しいですが、遅くなります。
美しいものには棘があるわけですよ。
まとめ
さらっとPrologでJavaScriptっぽい四則演算の処理を書いてみました。慣れれば、5分くらいで書けると思うのでLTでサクッと書いてみてはいかがでしょうか?