back numbers

6.20.2008

Prologはマクロ

do something with every element of a list and do it elegantly (comp.lang.prolog)
当初はmaplist/3かfoldingに関する質問かと思われた投稿だったが、リスト要素に任意の処理手順(複数)を適用する方法についてだと分かり、Jan Wielemaker氏が面白い論文とサンプルを引用してくれた。"任意の処理"を考えている時点で、これは高階論理の問題なわけだが、Prologでもちゃんと(そして簡単に)解決出来る。問題にパフォーマンスが含まれていなければ、だが。

他の言語ではマクロは一大機能である。幸いにしてPrologでは一大機能ではなく、当然の機能である。のだが、その辺りを解説してくれる書籍が今となっては手に入り難い。マクロ機能は基本的に単一化の恩恵なのだが、感覚的にはC++で演算子オーバーロードとtemplateを多用するものに近いだろう。例えばルールを記述する演算子 :- は ISO Prolog を起動した時点では次のように登録されている。
op(1200, xfx, ':-').

優先度が1200(もっとも低い)で二項演算子で結合性を持たないという意味である。このデータベースは動的に書き換え可能である。これに限らずASCII文字や(対応していれば)UNICODEも全て演算子テーブルに登録可能である。ただし , . ( ) は例外。特に . は consing となる。

Prologの演算子テーブルの表記は、慣れないとちょっと分かり辛い。二番目の引数は次のような意味に整理される。

表記|   解釈
-----+---------------
fx | 前置  無結合
fy | 前置  結合的
xf | 後置  無結合
yf | 後置  結合的
xfx | 中間子 無結合
xfy | 中間子 右結合
yfx | 中間子 左結合

例えば op(1105, xfy, |) というのは、優先度1105で中間演算子として機能し左結合的に解釈される、ので次のような解釈が成立する。表記 | の意味付けは consing で . となっている事に注意されたい。

?- [Head | [2, 3]] = '.'(1, Tail).
Head = 1,
Tail = [2, 3].


ちなみにJan Wielemaker氏が紹介してくれた do-macro の書き出しはこんな具合である。

:- op(1100, xfy, do).
(Specs do PredTemplete) :-
get_specs(Specs, Firsts, BaseHead, PreGoals, RecHead, AuxGoals, RecCall),
!,
call(PreGoals),
do_loop(Firsts, body(RecHead,(AuxGoals,PredTemplate),RecCall), BaseHead).

0 件のコメント:

tags

Profile

Taito, Tokyo, Japan
明けども明けども次の埒
hiro.kosh@gmail.com