Ce que je veux dire par un "wrapper de fonction transparent" pass-through "" est une fonction, appelons-la wrapper
, qui renvoie le résultat du passage de tous ses arguments à une autre fonction, appelons-la wrappee
.
Comment cela se fait-il dans Emacs Lisp?
NB: La wrapper
fonction idéale est agnostique quant à la wrappee
signature de la fonction; c'est-à-dire qu'il ne sait rien du nombre, des positions, des noms, etc. des wrappee
arguments de; il transmet simplement tous ses arguments à wrappee
, comme s'il wrappee
avait été celui initialement appelé. (Il n'est cependant pas nécessaire de jouer avec la pile d'appels pour remplacer l'appel à wrapper
par un appel à wrappee
.)
J'ai posté une réponse partielle à ma question:
(defun wrapper (&rest args) (apply 'wrappee args))
Cela ne fonctionne que lorsqu'il wrappee
n'est pas interactif. Apparemment, la façon dont les fonctions interactives obtiennent leurs arguments représente un "canal" différent de ce qui est couvert par l' (&rest args)
incantation. Ce dont j'ai encore besoin, par conséquent, est une wrappee
contrepartie également -agnostique de la (&rest args)
signature pour le cas où wrappee
est une fonction interactive .
(Cette question était motivée par un problème décrit dans cette question précédente .)
Dans le cas où une clarification supplémentaire de ce que je demande est nécessaire, voici quelques exemples, montrant les équivalents Python et JavaScript de ce que je recherche.
En Python, quelques méthodes standard pour implémenter un tel wrapper sont présentées ci-dessous:
def wrapper(*args, **kwargs):
return wrappee(*args, **kwargs)
# or
wrapper = lambda *args, **kwargs: wrappee(*args, **kwargs)
(Ici *args
signifie "tous les arguments positionnels", et **kwargs
signifie "tous les arguments de mots clés".)
L'équivalent JavaScript serait quelque chose comme ceci:
function wrapper () { return wrappee.apply(this, arguments); }
// or
wrapper = function () { return wrappee.apply(this, arguments); }
Pour mémoire, je ne suis pas d'accord que cette question est un doublon de Comment appliquer mapcar à une fonction avec plusieurs arguments . Je n'arrive pas à expliquer pourquoi, puisque les deux questions me semblent si différentes. C'est comme si on lui demandait "d'expliquer pourquoi une pomme ne devrait pas être considérée comme équivalente à une orange". La simple question est tellement folle, qu'on doute que l'on puisse jamais trouver une réponse qui satisfasse la personne qui la pose.
advice
choses suffisamment problématiques pour que je préfère rester à l'écart. En fait, la motivation pour cette question était d'essayer de trouver une solution à un problème autrement insoluble que j'ai avec une fonction conseillée ...interactive
spécification.Réponses:
Bien sûr, il est possible d'inclure la
interactive
spécification. Nous avons affaire ici à elisp ! (Lisp est le langage où les constructions les plus importantes sont des listes. Les formulaires appelables ne sont que des listes. Vous pouvez donc les construire à votre guise.)Application: vous souhaitez ajouter automatiquement certaines fonctionnalités à certaines fonctions. Les fonctions étendues doivent recevoir de nouveaux noms afin que cela
defadvice
ne s'applique pas.D'abord une version qui correspond tout à fait à votre objectif. Nous définissons la cellule de fonction (
fset
) du symbolewrapper
avec toutes les informations requiseswrappee
et ajoutons nos éléments supplémentaires.Cela fonctionne pour les deux
wrappee
définitions. La première version dewrappee
est interactive, la seconde ne l'est pas.Mais il est plus pratique de définir une macro qui construit les fonctions étendues. Avec cela, nous pouvons même spécifier les noms de fonction par la suite. (Bon pour une version automatisée.)
Après avoir exécuté le code ci-dessous, vous pouvez appeler de manière
wrapper-interactive
interactive etwrapper-non-interactive
non interactive.Remarque, jusqu'à présent, je n'ai pas encore trouvé de moyen de transférer les formulaires de déclaration, mais cela devrait également être possible.
la source
edebug
. En outre, il existe des fonctions où lainteractive
spécification-est considérablement plus grande que le corps de la fonction. Dans de tels cas, la réécriture de lainteractive
spécification peut être assez fastidieuse. La question et la réponse portent sur les principes requis.J'ai dû résoudre un problème très similaire dans
nadvice.el
, alors voici une solution (qui utilise une partie du code de nadvice.el):Par rapport aux autres solutions publiées jusqu'à présent, celle-ci a l'avantage de fonctionner correctement si elle
wrappee
est redéfinie avec une spécification interactive différente (c'est-à-dire qu'elle ne continuera pas à utiliser l'ancienne spécification).Bien sûr, si vous voulez que votre emballage soit vraiment transparent, vous pouvez le faire plus simplement:
la source
advice-eval-interactive-spec
comme suggéré ici, je peux construire la spécification interactive qui correspond à ce wrapper dynamique.called-interactively-p
revenirt
enwrappee
? Il n'y en afuncall-interactively
pasapply-interactively
(apply #'funcall-interactively #'wrappee args)
si vous le souhaitez. Mais vous ne devriez le faire que si la fonction est appelée de manière interactive, donc quelque chose comme(apply (if (called-interactively-p 'any) #'funcall-interactively #'funcall) #'wrappee args)
.edit: la réponse de Tobias est plus agréable que cela, car elle obtient la forme interactive précise et la docstring de la fonction encapsulée.
En combinant les réponses d'Aaron Harris et de kjo, vous pourriez utiliser quelque chose comme:
Usage:
Habillage d'appel avec l'un des éléments suivants:
M-x
wrapper-func
la source