ここには 2 つの問題があります。他の回答が指摘しているように、最初は構文の問題です。質問で言及されている2番目は、スコープの問題です。
構文の問題
Emacs Lisp (およびLisp-2(f args...)
ファミリーの他の Lisp) では、関数呼び出しはwheref
が関数値を持つシンボルまたはlambda
式のように見えます。例えば、
(list 1 2 3)
=> (1 2 3)
list
関数バインディングがあるためです。また、
((lambda (x y) (list x x y y)) 1 2)
=> (1 1 2 2)
表現だから(lambda (x y) (list x x y y))
。lambda
ただし、値が関数である何かを使用することはできません。
(let ((id (lambda (x) x)))
(id 3))
信号 a Lisp error: (void-function id)
。しかし、次を使用して関数値を呼び出すことができますfuncall
。
(let ((id (lambda (x) x)))
(funcall id 3))
=> 3
注: これは妥当な見方ですが、実際にはもう少し複雑です。詳細および関数間接化などの難解なビットについては、マニュアルの9.2 フォームの種類を参照してください。
これで、構文の問題に対処できます。どの関数がどの引数を取得しているかを示すために少し再フォーマットされた元のコードは次のとおりです。
(((lambda (b)
(lambda (a)
(+ b a)))
3)
5)
私が理解しているように、その意図は、最初(lambda (b) ...)
に引数3
を指定して呼び出して、無名関数を取得すること(lambda (a) ...)
です。Emacs Lisp では、次のようになります。
((lambda (b)
(lambda (a)
(+ b a)))
3)
=> (lambda (a) (+ b a))
ここで、返された無名関数を で呼び出すことも必要です5
。私たちはそれを行うために使用funcall
します:
(funcall ((lambda (b)
(lambda (a)
(+ b a)))
3)
5)
スコーピングの問題
残念なことに、このコードはLisp error: (void-variable b)
. ここで、動的スコープと字句スコープの問題に最終的に遭遇します。変数b
は動的にバインドされているため、その値は無名関数で保持されません(lambda (a) (+ b a))
。フォーム全体をバインドするもので囲み、何が起こるかを確認することで、これが起こっていることを確認できますb
。
(let ((b 100))
(funcall ((lambda (b)
(lambda (a)
(+ b a)))
3)
5))
=> 105
私はあまり Emacs Lisp ハッカーではないので、Emacs でレキシカル クロージャを取得する最善の方法がわかりません。Emacs 24 にはそれがあると読みましたが、ここではまだ 23 です。ただし、この回答に基づいて、lexical-let
必要な結果を得るために使用できます。
(funcall ((lambda (b)
(lexical-let ((b b))
(lambda (a)
(+ b a))))
3)
5)
=> 8
lexical-let
必要な字句バインディングを確立して、無名関数(lambda (a) ...)
が3
それを保持できるようにします。より具体的には、 の字句バインディングを導入しました。参照するのb
はその字句バインディングです(lambda (a) …)
。実際、返された無名関数を見ると、単純な(lambda (a) (+ b a))
ではなく、より複雑な (そしてあまり役に立たない) 方法で出力されます。
((lambda (b)
(lexical-let ((b b))
(lambda (a)
(+ b a))))
3)
=> (lambda (&rest --cl-rest--) (apply (lambda (G27322 a) (+ ... a)) (quote --b--) --cl-rest--))
余談ですが、字句的にバインドされた変数b
が動的にバインドされた変数と同じ名前であることは問題ではありませんb
。(lexical-let ((c b)) ... (+ c a) ...)
代わりに を使用することもできました。