Was ich mit einem "transparenten 'Pass-Through'-Funktions-Wrapper" meine, ist eine Funktion, nennen wir sie wrapper
, die das Ergebnis aus der Übergabe aller Argumente an eine andere Funktion zurückgibt, nennen wir sie wrappee
.
Wie geht das in Emacs Lisp?
NB: Die ideale wrapper
Funktion ist unabhängig von der wrappee
Signatur der Funktion. dh es weiß nichts über die Anzahl, Positionen, Namen usw. der wrappee
Argumente; es gibt einfach alle seine Argumente an weiter wrappee
, als wäre wrappee
es das ursprünglich genannte gewesen. (Es ist jedoch nicht erforderlich, sich mit dem Aufrufstapel herumzuschlagen, um den Aufruf von wrapper
durch einen Aufruf von zu ersetzen wrappee
.)
Ich habe eine teilweise Antwort auf meine Frage gepostet :
(defun wrapper (&rest args) (apply 'wrappee args))
Dies funktioniert nur, wenn wrappee
es nicht interaktiv ist. Anscheinend stellt die Art und Weise, wie interaktive Funktionen ihre Argumente erhalten, einen anderen "Kanal" dar als die (&rest args)
Beschwörung. Was ich daher noch brauche, ist ein ebenso wrappee
-agnostisches Gegenstück zur (&rest args)
Signatur für den Fall, dass wrappee
es sich um eine interaktive Funktion handelt.
(Diese Frage wurde durch ein in dieser früheren Frage beschriebenes Problem motiviert .)
Für den Fall, dass weitere Erläuterungen zu dem, wonach ich frage, erforderlich sind, finden Sie nachfolgend einige Beispiele, die die Python- und JavaScript-Entsprechungen dessen zeigen, wonach ich suche.
In Python werden im Folgenden einige Standardmethoden zum Implementieren eines solchen Wrappers gezeigt:
def wrapper(*args, **kwargs):
return wrappee(*args, **kwargs)
# or
wrapper = lambda *args, **kwargs: wrappee(*args, **kwargs)
(Hier *args
steht für "alle Positionsargumente" und **kwargs
für "alle Schlüsselwortargumente".)
Das JavaScript-Äquivalent wäre ungefähr so:
function wrapper () { return wrappee.apply(this, arguments); }
// or
wrapper = function () { return wrappee.apply(this, arguments); }
Ich bin nicht der Meinung, dass diese Frage ein Duplikat von Wie man Mapcar auf eine Funktion mit mehreren Argumenten anwendet . Ich kann nicht erklären, warum, da die beiden Fragen für mich so offensichtlich unterschiedlich aussehen. Es ist, als würde man gefragt, "warum ein Apfel nicht als gleichwertig mit einer Orange angesehen werden sollte". Die bloße Frage ist so verrückt, dass man bezweifelt, jemals eine Antwort finden zu können, die die fragende Person zufriedenstellt.
advice
Zeug problematisch genug, dass ich mich lieber davon fernhalten möchte. Tatsächlich bestand die Motivation für diese Frage darin, eine Lösung für ein ansonsten unlösbares Problem zu finden, das ich mit einer empfohlenen Funktion habe ...interactive
Spezifikation angeben.Antworten:
Natürlich ist es inklusive der
interactive
Spezifikation möglich. Wir haben es hier mit elisp zu tun ! (Lisp ist die Sprache, in der die wichtigsten Konstrukte Listen sind. Aufrufbare Formulare sind nur Listen. Sie können sie also nach Ihren Wünschen erstellen.)Anwendung: Sie möchten einigen Funktionen automatisch einige Funktionen hinzufügen. Die erweiterten Funktionen sollten neue Namen erhalten, damit sie
defadvice
nicht zutreffen.Zuerst eine Version, die genau zu Ihrem Zweck passt. Wir setzen die Funktionszelle (
fset
) des Symbolswrapper
mit allen erforderlichen Informationen auswrappee
und fügen unsere zusätzlichen Inhalte hinzu.Es funktioniert für beide
wrappee
Definitionen. Die erste Version vonwrappee
ist interaktiv, die zweite nicht.Es ist jedoch bequemer, ein Makro zu definieren, das die erweiterten Funktionen erstellt. Damit können wir sogar die Funktionsnamen nachträglich angeben. (Gut für eine automatisierte Version.)
Nachdem Sie den folgenden Code ausgeführt haben, können Sie
wrapper-interactive
interaktiv undwrapper-non-interactive
nicht interaktiv aufrufen .Beachten Sie, dass ich bisher noch keine Möglichkeit gefunden habe, die Deklarationsformulare zu übertragen, aber das sollte auch möglich sein.
quelle
edebug
. Darüber hinaus gibt es Funktionen, bei denen dieinteractive
Spezifikation erheblich größer ist als der Funktionskörper. In solchen Fällen kann das Umschreiben derinteractive
Spezifikation ziemlich mühsam sein. Die Frage und die Antwort richten sich nach den erforderlichen Grundsätzen.Ich musste ein sehr ähnliches Problem in lösen
nadvice.el
, daher hier eine Lösung (die einen Teil des Codes von nadvice.el verwendet):Im Vergleich zu den anderen bisher veröffentlichten Lösungen hat diese den Vorteil, dass sie korrekt funktioniert, wenn sie
wrappee
mit einer anderen interaktiven Spezifikation neu definiert wird (dh die alte Spezifikation wird nicht weiter verwendet).Wenn Sie möchten, dass Ihr Wrapper wirklich transparent ist, können Sie dies natürlich einfacher tun:
quelle
advice-eval-interactive-spec
den hier vorgeschlagenen Informationen kann ich die interaktive Spezifikation erstellen, die diesem dynamischen Wrapper entspricht.called-interactively-p
Rückkehrt
inwrappee
? Es gibtfuncall-interactively
aber keineapply-interactively
(apply #'funcall-interactively #'wrappee args)
wenn du willst. Aber Sie sollten es nur tun, wenn die Funktion interaktiv aufgerufen wird, also so etwas wie(apply (if (called-interactively-p 'any) #'funcall-interactively #'funcall) #'wrappee args)
.edit: Tobias 'Antwort ist schöner als diese, da sie die genaue interaktive Form und Dokumentation der umschlossenen Funktion erhält.
Wenn Sie die Antworten von Aaron Harris und kjo kombinieren, könnten Sie Folgendes verwenden:
Verwendungszweck:
Rufen Sie den Wrapper mit einer der folgenden Optionen auf:
M-x
wrapper-func
quelle