elisp функционирует как параметры и как возвращаемое значение - PullRequest
10 голосов
/ 19 марта 2009

У меня есть следующий код

(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 ]

19 голосов
/ 19 марта 2009

Этот стиль программирования не работает в простом Emacs Lisp. Emacs Lisp использует динамическое связывание, а языки, такие как Scheme и Common Lisp, используют лексическое связывание. Ваш код раскрывает разницу. См .: Степень в Emacs Lisp

См. Также этот вопрос: Как мне сделать замыкания в Emacs Lisp? и «решение» с помощью lexical-let. lexical-let - это расширение для Emacs Lisp в пакете "cl".

Смотрите также: начиная с Emacs 24.1 существует необязательное лексическое связывание . Узнайте, как его использовать: используя лексическое связывание .

12 голосов
/ 19 марта 2009

Хитрый вопрос, но, наконец, выяснил это. Проблема в том, что #' в определении avg-dump заставляет компилятор компилировать лямбда-функцию в момент времени , когда сама avg-dump компилируется , до того, как станет известно фактическое значение f. Вам нужно отложить компиляцию этой функции на более поздний момент времени, , когда avg-dump называется , например:

(defun avg-damp (f)
   `(lambda(x) (/ (+ (funcall ,f x) x) 2.0)))

(funcall (avg-damp #'(lambda(v) (* v v))) 10)

Обратное цитирование делает свое дело.

Редактировать : Конечно, вся проблема исчезнет, ​​если вы определите среднюю влажность в неторопливой форме, например:

(defun avg-damp (f x)
   (/ (+ (funcall f x) x) 2.0))

(funcall 'avg-damp #'(lambda(v) (* v v)) 10)

Но я думаю, у вас есть причины не делать этого.

...