「Makefileの書き方:プログラミング言語Make」のコメント欄で、shiroさんから「引数付き関数もユーザー定義できるよ」とご指摘いただきました。
http://www.gnu.org/software/automake/manual/make/index.htmlを見てみたら、最近のGNU Makeでは引数を扱えることが判明。例えば、次のように使えます。
SUBDIRS := src include testfiles = $(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言語でリスト処理関数を書こうとしたらうまくいきませんでした。再帰呼び出しが禁止されているんですよ。関数型言語で再帰が使えないと、、、、トホホですわ。[追記]いや、再帰呼び出しできるようです。コメント欄と次のエントリーの最後参照。[追記]