1

私はemacslispでクロージャを適用しようとしています。ここに投稿があります: Emacs Lispでクロージャを行うにはどうすればよいですか?

次のようなコードで:

(defun foo(x) `(lambda()、x))(message(string(funcall(foo 66))))

しかし、emacsのドキュメントに従って、ラムダは'(lambda()x)==>のようにフォーマットする必要があります。このフォーマットを使用すると、エラーが発生します:変数がvoidであるためシンボルの値:x

「、」が「()」と「x」の間に追加されると、すべてが正しくなります。

なんで?

4

2 に答える 2

3

これは、Emacs Lispが動的にスコープされ、空きfooの場合はラムダを返すために発生しますx。それはエラーがあなたに言うことです。

Emacs Lispでクロージャを実行するにはlexical-let、字句バインディングをシミュレートするため、実際のクロージャを作成できるようにする必要があります。

(defun foo (x)
  (lexical-let ((x x))
               (lambda () x)))

(message (string (funcall (foo 66))))

EmacsWikiからのリンクは次のとおりです。

  1. 動的バインディングとレキシカルバインディング
  2. 偽のクロージャ

x次のようなletで定義できた可能性があることに注意してください。

(defun foo (x)
  (lambda () x))

(message (string (let ((x 66)) (funcall 
                                (foo 'i-dont-care)))))
于 2011-12-23T10:21:18.787 に答える
0

この回答は、@Daimrodの正解の最初の部分の背後にある詳細を示しています。

あなたの質問は、なぜこれが機能するのかということです。

(defun foo (x) `(lambda () ,x)) (message (string (funcall (foo 66))))

これは機能しません:

(defun foo (x) '(lambda () x)) (message (string (funcall (foo 66))))

'まず、 EmacsではLispラムダ形式は自己評価型であるため、2番目の引用符( )は不要です。つまり、'(lambda (...) ...)通常はと同じように動作し(lambda (...) ...)ます。

しかし、quote( )`の代わりにbackquote()は何をします'

バッククォートされた式の中で、コンマ(,)は、次の式をその値で置き換える、つまり評価することを意味します。したがって、この:

`(lambda () ,x)

lambdaは、最初の要素がシンボル(評価されていない)、2番目の要素が()(評価されていない)、3番目の要素が変数のであるリストを作成して返すことを意味しますx。これは、関数を使用するこのコードを評価することと同じですlist

(list 'lambda '() x)

それがあなたが望むものです:現在の値(この場合、関数内の値、つまり's引数の値)に置き換えます。 xfoofoo

でも、これ:

'(lambda () x)

(同様に、ラムダ形式は自己評価であるため、(lambda () x))は次のリストを返します(lambda () x)。そして、それが動的スコープ(Emacs Lispのデフォルトのスコープレジーム)を使用して評価された場合、xバインドされていません-それは価値がありません。そのため、void-variableエラーが発生します。

于 2020-05-08T23:29:24.307 に答える