2009-03-19 6 views
10

je le code suivantfonctions elisp en tant que paramètres et que la valeur de retour

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

Un appel

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

rendements 55,0 (la valeur correcte) dans SBCL mais se bloque avec la pile suivante en 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) 

Comment puis-je le faire fonctionner dans Emacs Lisp?

Répondre

12

Une question délicate, mais finalement compris. Le problème est que #' dans la définition de avg-damp fait que le compilateur compile la fonction lambda au moment quand avg-damp lui-même est compilé, avant que la valeur réelle de f soit connue. Vous avez besoin de retarder la compilation de cette fonction à un point plus tard dans le temps, est appelé quand, comme avg-humide ceci:

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

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

Backquoting fait l'affaire.

Modifier: Bien sûr, le problème disparaît si vous définissez avg-humide sous une forme uncurried, comme ceci:

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

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

Mais je suppose que vous avez vos raisons de ne pas le faire.

19

Ce style de programmation ne fonctionne pas en mode Emacs Lisp simple. Emacs Lisp utilise la liaison dynamique et les langages comme Scheme et Common Lisp utilisent la liaison lexicale. Votre code expose la différence. Voir: Extent in Emacs Lisp

Voir aussi cette question: How do I do closures in Emacs Lisp? et la 'solution' avec lexical-let. lexical-let est une extension pour Emacs Lisp dans le paquet "cl".

Voir aussi: puisque Emacs 24.1 est optionnel lexical binding. Apprenez à l'utiliser: using lexical binding.

Questions connexes