функции elisp как параметры и как возвращаемое значение
у меня есть следующий код
(defun avg-damp(f)
#'(lambda(x) (/ (+ (funcall f x) x) 2.0)))
вызов
(funcall (avg-damp #'(lambda(v) (* v v))) 10)
возвращает 55.0 (правильное значение) в SBCL, но аварийно завершает работу со следующим стеком в emacs lisp
Debugger entered--Lisp error: (void-variable f)
(funcall f x)
(+ (funcall f x) x)
(/ (+ (funcall f x) x) 2.0)
(lambda (x) (/ (+ ... x) 2.0))(10)
funcall((lambda (x) (/ (+ ... x) 2.0)) 10)
eval((funcall (avg-damp (function ...)) 10))
eval-last-sexp-1(nil)
eval-last-sexp(nil)
call-interactively(eval-last-sexp)
как я могу заставить его работать в Emacs lisp?
2 ответов
сложный вопрос, но, наконец, понял это. Проблема в том, что #'
в определении avg-damp компилятор компилирует лямбда-функцию в момент когда avg-damp сам компилируется, прежде чем будет известно фактическое значение f. Вам нужно отложить компиляцию этой функции на более поздний момент времени,когда avg-damp вызывается, например:
(defun avg-damp (f)
`(lambda(x) (/ (+ (funcall ,f x) x) 2.0)))
(funcall (avg-damp #'(lambda(v) (* v v))) 10)
Backquoting делает трюк.
редактировать: Конечно, вся проблема уходит, если вы определяете avg-damp в неторопливой форме, например:
(defun avg-damp (f x)
(/ (+ (funcall f x) x) 2.0))
(funcall 'avg-damp #'(lambda(v) (* v v)) 10)
но я думаю, у вас есть причины не делать этого.
этот стиль программирования не работает в обычном Emacs Lisp. Emacs Lisp использует динамическую привязку, а такие языки, как Scheme и Common Lisp, используют лексическую привязку. Ваш код раскрывает разницу. См.: экстент в Emacs Lisp
см. Также этот вопрос: как сделать закрытие в Emacs Lisp? и "решение" с лексическим-пусть. lexical-let является расширением для Emacs Lisp в пакете "cl".
см. также: поскольку Emacs 24.1 существует необязательно лексические привязки. Узнайте, как его использовать:использование лексической привязки.