当初は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 件のコメント:
コメントを投稿