2007-11-01

Prolog (4)

Prologは高級言語に属すると思うのですが、昨今のプログラミング言語を見るとLLは言うに及ばずc++でもSTLという便利なライブラリが付いてきます。最もそういったユーティリティはPrologでは大体が簡単に作れるものなので、マイライブラリを構築している人が大半かと思われます。とりあえず定番どころからそういったものを晒して行く事にします。

リストオブジェクトが使えるとプログラマの本能は、要素に対する関係を記述してやりたくなります。まずは個々の要素と関係を満足する要素のリストを作るmapです。

% map/3
map(_, [], []).
map(Fn, [X|Xs], [Y|Ys]) :-
G =.. [Fn, X, Y],
call(G),
map(Fn, Xs, Ys).
% inc/2
inc(X, Y) :- Y is X + 1.

?- map(inc, [1,2,3], L).
L = [2,3,4]


続いて関係を満足した要素だけからなるリストを作るfilterです。

% filter/3
filter(_, [], []).
filter(Pr, [X|Xs], [X|Ys]) :-
G =.. [Pr, X],
call(G),
filter(Pr, Xs, Ys).
filter(Pr, [_|Xs], Ys) :-
filter(Pr, Xs, Ys).

?- filter(number, [a,1,b,2,3,4], L).
L = [1,2,3,4]


さらに一般的な高階関数fold(l/r)はこんな感じです。

% foldl/3
foldl(_, X, [], X).
foldl(Fn, Y1, [X|Xs], Y) :-
G =.. [Fn, Y1, X, Y2],
call(G),
foldl(Fn, Y2, Xs, Y).

?- foldl(plus, 0, [1,2,3,4], Sum).
Sum = 10

% foldr/3
foldr(_, X, [], X).
foldr(Fn, Y1, [X|Xs], Y) :-
foldr(Fn, Y1, Xs, Y2),
G =.. [Fn, X, Y2, Y],
call(G).
% minus/3
minus(X, Y, Z) :- plus(Z, Y, X).

?- foldr(minus, 0, [1,2,3,4], Q).
Q = -2


ところで上で出てきたオペレータに入門書では見慣れないものがありますね。=..って奴です。コイツは複合項(Compound TermあるいはStructureとも呼ぶ)を作成する演算子(正確には(=..)/2で自由変数とリストが引数)です。call/1は引数として渡されたゴールを実行しますので、それを用意しているわけです。

G =.. [Fn, X, Y].
G = Fn(X, Y)

処理系によっては次のようにしてcallを使えるものもあります。

call(Fn, X, Y). % Fn(X, Y) to be executed.

2007-10-29

.emacs (3)

Emacsでc++のソースを編集すると名前空間がインデント付いてとても嫌なので。あとヘッダファイルは標準ではc-modeなのでこれをc++-modeに加える。

(setq auto-mode-alist
(append '(("\\.h$" . c++-mode))
auto-mode-alist))
(add-hook 'c++-mode-hook
'(lambda ()
(c-set-style "gnu")
(c-set-offset 'innamespace 0)))

ちなみにGNUスタイルは個人的には好きなのでそのまま。ブロックインデント時にカーリーブラケットの有無でインデントが変わるのは視認性が高まって良い。