4

昔、Emacs はレキシカル スコープをサポートしていませんでした。当時、人々は動的スコープの特定の落とし穴にどのように対処していたのだろうか。

Alice が で定義された関数(Bob によって書かれた関数型プログラミングのための多くの関数を提供するライブラリであると仮定します)my-insert-stuffに依存するコマンドを書き、関数を何度も繰り返し呼び出すためのものであるとします。fp-repeatfp.elfp-repeat

init.elアリスからの内容の一部:

(require 'fp)

(defun my-insert-stuff ()
  (interactive)
  ;; inserts "1111111111\n2222222222\n3333333333" to current buffer
  (dolist (i (list "1" "2" "3"))
    (fp-repeat 10
               (lambda ()
                 (insert i)))
    (insert "\n")))

fp.elボブからのコンテンツの一部:

(defun fp-repeat (n func)
  "Calls FUNC repeatedly, N times."
  (dotimes (i n)
    (funcall func)))

Alice はすぐに、コマンドが期待どおりに機能しないことに気付きます。これは、アリスの使用iとボブの使用がi衝突するためです。昔は、この種の衝突が起こらないようにするために、アリスまたはボブと一緒に何ができたでしょうか?

おそらく、ボブは docstring を次のように変更できます。

"Calls FUNC repeatedly, N times.
Warning: Never use i, n, func in FUNC body as nonlocal variables."
4

3 に答える 3

5

Emacs がこの問題に対処した方法は、非常に厳密な規則に従うことです: 高階関数 ( your などfp-repeat) を作成する Elisp プログラマーは、一筋の光がその関数が光線が機能しないときは、毎日の祈りを行うことが期待されていました (Emacs の教会では常に良い考えです)。

于 2013-08-15T13:35:09.493 に答える
3

lunaryorn と Stefan が言ったことに加えて:

あなたが与えた特定の例では、渡された funarg は、実際には変数をまったくfp-repeat必要としません。i

iつまり、 AS A VARIABLEで何もする必要はありません。つまりi、関数が呼び出されたときに、特定の時間または特定のコンテキスト (環境) で値が決定される特定の SYMBOL として使用する必要はありません。

その関数が実際に必要とするのは、関数が定義されiたときと場所のVALUE だけです。この特定のケースで変数を使用するのはやり過ぎです --- その値だけが必要です。

したがって、針に糸を通す別の方法は、関数の定義、つまり式で変数の値を置き換えることです。lambda

 (defun my-insert-stuff ()
   (interactive)
   (dolist (i (list "1" "2" "3"))
     (fp-repeat 10 `(lambda () (insert ',i)))
     (insert "\n")))

これはうまくいきます。変数がないため、変数のキャプチャの可能性はありません

欠点は、コンパイル時に関数がないことです: LIST が構築され、そのリストcarlambda実行時に評価され、関数として解釈されます。

具体的なユースケースによっては、これは便利な方法です。はい、それは、実際に変数を使用する必要があるコンテキストを区別する必要があることを意味します (関数が行うことはi、値だけでなく VARIABLE を使用します)。

于 2013-08-15T14:35:48.023 に答える