Comment créer une fonction temporaire dans Emacs Lisp
Je fais des appels fastidieux à un tas de fonctions, mais les paramètres seront déterminés à l'exécution. J'ai écrit une fonction simple pour garder mon code sec mais lui donner un nom est inutile. Je n'utilise cette fonction nulle part ailleurs.
J'essaie de le faire comme je le ferais dans Scheme, mais j'obtiens une erreur void-function
:
(let ((do-work (lambda (x y z)
(do-x x)
(do-y y)
;; etc
)))
(cond (test-1 (do-work 'a 'b 'c))
(test-2 (do-work 'i 'j 'k))))
Je pourrais tout coller dans un apply
(par exemple, (apply (lambda ...) (cond ...))
) mais ce n'est pas très lisible. Est-il un meilleur moyen?
3 réponses
Comme les autres Lisp (mais pas Scheme), Emacs Lisp a des espaces de noms distincts pour les variables et les fonctions (c'est-à-dire un ‘Lisp2’, pas un " Lisp1’; Voir questions techniques de séparation dans les cellules de fonction et les cellules de valeur pour l'origine et la signification de ces termes).
Vous devrez utiliser funcall
ou apply
pour appeler un lambda (ou une autre fonction) stocké dans une variable.
(cond (test-1 (funcall do-work 'a 'b 'c))
(test-2 (funcall do-work 'i 'j 'k))
Utiliser funcall
si vous envoyez toujours le même nombre de argument. Utilisez apply
Si vous devez pouvoir envoyer un nombre variable d'arguments.
Le mécanisme interne est que chaque symbole a plusieurs "cellules".
Quelle cellule est utilisée dépend de où le symbole est sous une forme évaluée .
Lorsqu'un symbole est le premier élément d'une forme évaluée, sa cellule "fonction" est utilisée.
Dans toute autre position, sa cellule" valeur " est utilisée .
Dans votre code, do-work
a la fonction dans sa cellule de valeur.
Pour y accéder en tant que la fonction que vous utilisez funcall
ou apply
.
S'il était dans la cellule de fonction, vous pourriez l'appeler directement en utilisant son nom comme voiture d'un formulaire évalué.
Vous pouvez accomplir cela avec flet
ou labels
de la cl package.
Faites (require 'cl)
pour extraire le paquet Common Lisp, puis utilisez flet
au lieu de let
:
(flet ((do-work (x y z)
(do-x x)
(do-y y)
;; etc
))
(cond (test-1 (do-work 'a 'b 'c))
(test-2 (do-work 'i 'j 'k))))
Vous pouvez le faire de la manière ANSI Common Lisp (bien que je pense qu'il y a des développements Emacs qui vous donneront des regards méchants):
(flet ((do-work (x y z)
(do-x x)
(do-y y)
;; etc
))
(cond (test-1 (do-work 'a 'b 'c))
(test-2 (do-work 'i 'j 'k))))
Je ne sais pas si vous serez d'abord (require 'cl)
(ou cl-macs
?) pour utiliser flet. Si vous voulez définir des fonctions récursives, vous devrez utiliser labels
IIRC.