このブログの更新は Twitterアカウント @m_hiyama で通知されます。
Follow @m_hiyama

メールでのご連絡は hiyama{at}chimaira{dot}org まで。

はじめてのメールはスパムと判定されることがあります。最初は、信頼されているドメインから差し障りのない文面を送っていただけると、スパムと判定されにくいと思います。

参照用 記事

プログラミング言語Make 補遺:引数付きの関数

「Makefileの書き方:プログラミング言語Make」のコメント欄で、shiroさんから「引数付き関数もユーザー定義できるよ」とご指摘いただきました。

http://www.gnu.org/software/automake/manual/make/index.htmlを見てみたら、最近のGNU Makeでは引数を扱えることが判明。例えば、次のように使えます。


SUBDIRS := src include test

files = $(wildcard $(1)/*.erl) $(wildcard $(1)/*.hrl)

ALL_FILES := $(foreach dir,$(SUBDIRS),$(call files,$(dir)))

filesが引数付き関数(Make用語ではパラメータを持つ再帰的変数)です(($(wildcard $(1)/*.erl) $(wildcard $(1)/*.hrl)は、$(wildcard $(1)/*.erl $(1)/*.hrl)としても結果は変わりません。))。仮引数(パラメータ)は番号$(1), $(2), …で識別します。残念ながら名前は使えません。

ユーザー定義関数を呼び出すときは組み込み関数callを使います。例えば、$(call files,src)のように。単なる変数参照も呼び出しなので、$(FOO)の代わりに$(call FOO)でも同じです。

組み込み関数foreachは、確かにスクリプト言語のforeachとも似ているんですが、動作は関数型言語マッピング関数と同じです。リストに沿って処理を繰り返して、結果もリストにまとめて返されます。

上のMakeプログラムをLispに翻訳すればこんな感じでしょう。


(setq SUBDIRS '("src" "include" "test"))

(defun files (dir)
(append
(wildcard (concat dir "/*.erl"))
(wildcard (concat dir "/*.hrl"))))

(setq ALL_FILES
(flatten (mapcar (function files) SUBDIRS)))

flattenは、リストの入れ子を(それがあれば)はずして平らなリストにする関数のつもり。例えば:


(defun flatten (lis)
(cond ((null lis) lis)
((not (consp lis)) (list lis))
(t (append (flatten (car lis)) (flatten (cdr lis))))))

Make言語では、ちゃんとしたリストはありませんが、語(ワード)を空白をはさんで並べた文字列はリスト扱いできます。

ちなみに、Make言語でリスト処理関数を書こうとしたらうまくいきませんでした。再帰呼び出しが禁止されているんですよ。関数型言語再帰が使えないと、、、、トホホですわ。[追記]いや、再帰呼び出しできるようです。コメント欄と次のエントリーの最後参照。[追記]