->
のならばなぁ。Prologだと使えるんだけど、単なる三項演算子か、',' でしかないしなぁ。ならばといえば Prolog のメダカ演算子が :-
ならばの逆の意味で、whereというか ここで
演算子だよなぁ。などと思い、日本語プログラミングを論理型言語で書けるとその変の理解が深まるのだよなぁ。
論理の世界には4つのならばがあって2つは論理式の中に現れるアンドと三項演算子でもう一つが規則定義の際に使う横棒、もう一つが証明木で使う横棒なんです。
ということで今日のテーマは、言語実装を趣味としてしている人々にとって足りない力があります。それが論理プログラミング力です。
今日はPrologのユーザー定義演算子を定義することで日本語プログラミング環境を簡単に構築し、その上で足し算ができるだけのインタプリタを作ります。
演算子定義
Prologはユーザー定義の優先順位付きの演算子を定義できます。
:- op(1200,xfx,ならば).
:- op(1000,xfy,かつ).
:- op(700,xfx,が).
:- op(500,xf,が整数).
このように定義すると1200の優先順位を持つ ならば
二項演算子と 1000 の優先順位をもつ かつ
二項演算子、700の優先順位を持つ が
二項演算子と、500の優先順位をもつ が整数
単項演算子を定義できます。
xfx,xfy,yfxの違いは結合性がないか、右結合か左結合の違いを表します。
項の展開
Prologには強力なマクロ機能のようなterm_expansionという機能があります。
term_expansionはリードマクロのように働きすべてのトップレベルの項を自由に書き換えられます。
term_expansion(B ならば A, A:-B).
と書くと、B ならば A.
というトップレベルの項を A :- B.
に書き換えることができます。
通常の述語は述語の定義で代替できますが、トップレベルの項の動きはterm_expansionを使わないと書き換えられないので使いました。
このterm_expansionはハイジニックなマクロというかプリプロセッサとして働くので何でもできちゃうんで凄いのですけど、ここでは演算子の置き換えさえできればいいので深入りはしません。
日本語述語の定義
integer(I) ならば I が整数.
call(A),call(B) ならば A かつ B.
I is E ならば I が E.
整数であることを調べる が整数/1
と、 論理積を表す かつ/2
、算術式を計算する が/2
の述語を定義します。
評価規則の定義
I が整数 ならば e(I,I).
e(E1,I1) かつ e(E2,I2) かつ I が I1+I2 ならば e(E1+E2,I).
整数を足し合わせるだけの言語の評価規則は2つ必要になります。
1つは整数であれば整数であることを返す規則。
もう一つは足し算であればその項を分解して評価し評価結果を足し合わせる規則です。
使い方
1ファイル内で使うには以下のように記述することで定義したインタプリタを実行して試すことができます。
:- e(1+2+3,R) かつ writeln(R) かつ R=6.
:- halt.
まとめ
Prologで演算子を定義し、その演算子を使って日本語プログラミング環境を構築、日本語でインタプリタを実装し、実際に使ってみました。
プログラム全体を以下に示します。
:- op(1200,xfx,ならば).
:- op(1000,xfy,かつ).
:- op(700,xfx,が).
:- op(500,xf,が整数).
term_expansion(B ならば A, A:-B).
integer(I) ならば I が整数.
call(A),call(B) ならば A かつ B.
I is E ならば I が E.
I が整数 ならば e(I,I).
e(E1,I1) かつ e(E2,I2) かつ I が I1+I2 ならば e(E1+E2,I).
:- e(1+2+3,R) かつ writeln(R) かつ R=6.
:- halt.
論理プログラミングは人工知能用言語としては古いかもしれませんが、操作的意味論や型理論の図式をネイティブの感覚で理解する上で有用です。高速に動作することはありませんが、述語論理を用いた形式的な論理的な思考をネイティブな感覚で理解する道具として使うと普通の奴らの上の更に上を行ける道具として使えるので、いい加減プログラミング言語の実装は飽きたよ。という方でも、そういえば論理プログラミングはよくわからんな。という方がいらっしゃったら、ちょっとだけいじってみると新たな境地にいざなってくれるかもしれません。