0

質問から関数をパラメータとして elisp に渡すにはどうすればよいですか? 関数をパラメーターとして関数に渡す方法を知っています。しかし、 もっと深く掘り下げる必要があります...

不自由な映画の引用はさておき、関数をパラメーターとして取り、[パラメーターとして取った関数を再び渡す] 自分自身を呼び出すことができる関数が必要です。次のスニペットを検討してください。

(defun dummy ()
  (message "Dummy"))

(defun func1 (func)
  (funcall func))

(defun func2 (func arg)
  (message "arg = %s" arg)
  (funcall func)
  (func2 'func (- arg 1)))

を呼び出す(func1 'dummy)と、期待される出力が得られます。

Dummy    
"Dummy"

呼び出す(func2 'dummy 4)と、次のエラー メッセージが表示されます。

arg = 4
Dummy
arg = 3
funcall: Symbol's function definition is void: func

ダミーへの 4 回の呼び出しを予期していましたが、2 回目の反復でfunc2は、最初の反復に渡された (そしてそこから渡された) 関数の知識が失われたようです。どんな助けでも大歓迎です!

4

3 に答える 3

4

おそらく、レキシカルスコープでこれを行うためのより良い方法があります。これは多かれ少なかれ Rosetta Code からの翻訳です。

(defun closure (y)
  `(lambda (&rest args) (apply (funcall ',y ',y) args)))

(defun Y (f)
  ((lambda (x) (funcall x x))
   `(lambda (y) (funcall ',f (closure y)))))

(defun factorial (f) 
  `(lambda (n)
     (if (zerop n) 1 
       (* n (funcall ,f (1- n))))))

(funcall (Y 'factorial) 5) ;; 120

Rosetta コードへのリンクは次のとおりです: http://rosettacode.org/wiki/Y_combinator同じことを実装する他の言語の束。Y-combinator は、固定小数点コンビネータのファミリからの構造です。大まかに言うと、再帰関数を実装する必要性をなくすという考えです (再帰関数を VM でコンパイル/実装する方法を考えると、再帰関数はより洗練されたものを必要とします)。Y-combinator は、すべての関数を機械的に非再帰形式に変換できるようにすることでこれを解決しますが、一般的には再帰を許可します。

公平を期すために言うと、上記のコードは再帰的な各ステップで新しい関数を作成するため、あまり良くありません。これは、最近まで、Emacs Lisp にはレキシカル バインディングがなかったためです (関数にそのレキシカル環境をキャプチャさせることはできませんでした)。つまり、Emacs Lisp 関数が宣言されたスコープ外で使用されると、バインドされた変数は、関数の現在のスコープから取得されます。上記の場合、そのようなバインドされた変数はf関数Y内および関数y内にありclosureます。幸いなことに、これらは既存の関数を指定する記号にすぎないため、マクロを使用してその動作を模倣することができます。

さて、Y-コンビネーターが行うこと:

  1. 元の関数を variable にキャプチャしますf

  2. 1 つの引数のラッパー関数を返します。これはf、順番に呼び出されたときに を呼び出し、Y-combinator によって使用されて

  3. 無制限の数の引数のラッパー関数を返します。

  4. 呼び出されたすべての引数を渡して元の関数を呼び出します。

この構造は、Y-combinator で使用される関数の構造も指定します。単一の引数を取り、関数 (これも同じ関数です) である必要があり、(任意の数の引数の) 関数を返す必要があります。外側のスコープから継承された関数を呼び出します。

まあ、それは少し気が遠くなることが知られています:)

于 2013-05-29T21:41:32.497 に答える
1

funcこれは、関数ではなく関数を呼び出そうとしているためですdummy

(したがって、「シンボルの関数定義が無効です: func」というエラーが表示されます。)

あなたがしたい:

(func2 func (- arg 1)))

いいえ:

(func2 'func (- arg 1)))
于 2013-05-29T21:24:55.537 に答える