In R gibt es eine allgemeine Funktion, die ein Muster aufruft, das so aussieht:
%Vor%Diese Wiederholung von Namen ist hilfreich, da sie potenziell heimtückische Fehler verhindert, wenn sich die Reihenfolge der Argumente des Kindes ändern sollte oder wenn eine zusätzliche Variable in die Liste eingefügt werden soll:
%Vor%Aber das wird mühsam, wenn die Namen der Argumente lang werden:
%Vor%Ich hätte gerne einen Weg, um die Sicherheit der benannten Parameter zu erhalten, ohne die Namen erneut eingeben zu müssen. Und ich wäre in der Lage, dies zu tun, wenn ich nur das Elternteil und nicht das Kind ändern kann. Ich würde mir so etwas vorstellen:
%Vor% Dabei wäre params()
eine neue Funktion, die die unbenannten Argumente basierend auf den Namen der Variablen in benannte Parameter umwandelt. Zum Beispiel:
Es gibt eine paar Funktionen in 'pryr', die dem nahe kommen, aber ich habe nicht herausgefunden, wie ich sie kombinieren kann, um das zu erreichen, was ich will. named_dots(c,b,a)
gibt list(c=c, b=b, a=a)
zurück, und standardise_call()
hat eine ähnliche Operation, aber ich habe nicht herausgefunden, wie man die Ergebnisse in etwas umwandeln kann, das an ein unmodifiziertes child()
übergeben werden kann.
Ich würde gerne eine Mischung aus impliziten und explizit benannten Parametern verwenden können:
%Vor%Es wäre auch schön, einige unbenannte Konstanten (keine Variablen) mischen zu können und sie als benannte Argumente behandeln zu lassen, wenn sie an das Kind übergeben werden.
%Vor%Aber auf eine nicht-R-Weise würde ich lieber Fehler auslösen, anstatt zu versuchen, sich mit den wahrscheinlichsten Programmierfehlern herumzuschlagen:
%Vor%Gibt es dafür bereits vorhandene Werkzeuge? Einfache Möglichkeiten, bestehende Funktionen zusammenzusetzen, um das zu tun, was ich will? Bessere Möglichkeiten, das gleiche Ziel zu erreichen, Sicherheit bei sich ändernden Parameterlisten ohne unhandliche Wiederholung zu erreichen? Verbesserungen an meiner vorgeschlagenen Syntax, um es noch sicherer zu machen?
Klärung der Vorabprämie : Die Funktionen parent()
und child()
sollten als unveränderbar betrachtet werden. Ich bin nicht daran interessiert, entweder mit einer anderen Schnittstelle zu verpacken. Stattdessen suche ich hier nach einer Möglichkeit, die vorgeschlagene params()
-Funktion in einer allgemeinen Weise zu schreiben, die die Liste der Argumente im laufenden Betrieb neu schreiben kann, so dass sowohl parent()
als auch child()
direkt mit einem sicheren aber verwendet werden können nicht ausführliche Syntax.
Klärung nach der Belohnung : Die Umkehrung der Eltern-Kind-Beziehung und die Verwendung von do.call () ist eine nützliche Technik, die ich hier nicht suche. Stattdessen suche ich nach einer Möglichkeit, ein '...' Argument zu akzeptieren, modifiziere es, um benannte Parameter zu haben, und gebe es dann in einer Form zurück, die die umschließende Funktion akzeptiert. Es ist möglich, dass, wie andere vorschlagen, dies wirklich unmöglich ist. Persönlich denke ich derzeit, dass es mit einer C-Level-Erweiterung möglich ist, und ich hoffe, dass diese Erweiterung bereits existiert. Vielleicht macht das vadr
-Paket, was ich will? Ссылка
Teilkredit : Ich fühle mich albern, wenn ich das Kopfgeld ablaufen lasse. Wenn es keine vollständigen Lösungen gibt, vergebe ich sie an jeden, der einen Konzeptnachweis für mindestens einen der notwendigen Schritte erbringt. Zum Beispiel, indem Sie ein '...' Argument innerhalb einer Funktion ändern und es dann an eine andere Funktion übergeben, ohne do.call () zu verwenden. Oder ein unmodifiziertes '...' Argument in einer Weise zurückgeben, dass das Elternteil es verwenden kann. Oder alles, was am besten zu einer direkten Lösung oder sogar zu einigen nützlichen Links führt: Ссылка < Aber ich zögere, es einer Antwort zuzuordnen, die mit der (ansonsten völlig vernünftigen) Prämisse beginnt: "Das willst du nicht", oder "das ist unmöglich, also hier ist eine Alternative".
Bounty ausgezeichnet : Es gibt mehrere wirklich nützliche und praktische Antworten, aber ich entschied mich dafür, das Kopfgeld an zu vergeben @crowding . Während er (wahrscheinlich richtig) behauptet, dass das, was ich will, unmöglich ist, denke ich, dass seine Antwort dem "idealistischen" Ansatz am nächsten kommt, den ich anstrebe. Ich denke auch, dass sein vadr -Paket ein guter Ausgangspunkt für eine Lösung sein könnte, egal ob es meinen (möglicherweise unrealistischen) Designzielen entspricht oder nicht. Die "akzeptierte Antwort" ist immer noch offen für den Fall, dass jemand einen Weg findet, das Unmögliche möglich zu machen. Danke für die anderen Antworten und Vorschläge, und hoffentlich werden sie jemandem helfen, die Teile für eine robustere R-Syntax zusammenzustellen.
Ich denke, der Versuch, die eingebaute Argument-Matching-Funktionalität von R
zu überschreiben, ist etwas gefährlich, also ist hier eine Lösung, die do.call
verwendet.
Es war unklar, wie viel von parent
veränderbar ist
Eine zweite Option basierend auf der "Magie" von write.csv
Sie können die Parameter nicht innerhalb des Funktionsaufrufs in eine Funktion ändern. Der nächste beste Weg wäre, einen einfachen Wrapper um den Anruf zu schreiben. Vielleicht kann so etwas helfen
%Vor%Und wir können mit etwas wie
testen %Vor% Beachten Sie, dass parent2
in der Parameterreihenfolge von child
robust ist, während parent
sich ändert.
Es ist nicht einfach, die genaue Syntax zu erhalten, die Sie vorschlagen. R wird langsam ausgewertet, so dass die Syntax, die in einem Argument zu einer Funktion erscheint, erst nach dem Start des Funktionsaufrufs betrachtet wird. Zu dem Zeitpunkt, an dem der Interpreter auf params()
stößt, hat er bereits den Aufruf von child()
gestartet und alle Argumente von child
gebunden und einen Teil des Codes child
ausgeführt. Die Argumente von child
können nicht umgeschrieben werden, nachdem das Pferd sozusagen den Stall verlassen hat.
(Die meisten nicht-faulen Sprachen würden das aus verschiedenen Gründen auch nicht zulassen)
Also muss die Syntax etwas sein, das die Verweise auf "Kind" und "Params" in seinen Argumenten hat. vadr
hat einen Operator %()%
, der funktionieren kann. Es wendet eine auf der rechten Seite angegebene Punktliste auf eine Funktion an, die auf der linken Seite angegeben ist. Du würdest also schreiben:
wobei params
seine Argumente in einer Punktliste abfängt und manipuliert:
Dies sollte ein Kommentar sein, aber es passt nicht zu den Grenzen. Ich empfehle Ihnen für Ihren Programmier-Ehrgeiz und Reinheit, aber ich denke, das Ziel ist unerreichbar. Angenommen, params
existiert und wendet es auf die Funktion list
an. Durch die Definition von params
, identical(list(a = a, b = b, c = c) , list(params(a, b, c))
. Daraus ergibt sich identical(a, params(a, b, c))
, indem das erste Element des ersten und zweiten Arguments von identical
genommen wird. Daraus folgt, dass params
nicht von seinen zweiten und späteren Argumenten abhängig ist, ein Widerspruch. Q.E.D. Aber ich denke deine Idee ist ein schönes Beispiel für DRY in R und ich bin vollkommen zufrieden mit do.call(f, params(a,b,c))
, das eine zusätzliche do.call hat, aber keine Wiederholung. Mit Ihrer Erlaubnis möchte ich es in mein Paket bettR integrieren, das verschiedene Ideen zur Verbesserung der R-Sprache sammelt. Eine verwandte Idee, mit der ich spielte, ist das Erstellen einer Funktion, die einer anderen Funktion erlaubt, fehlende Argumente aus dem aufrufenden Rahmen zu bekommen. Das heißt, anstatt f(a = a, b = b)
aufzurufen, könnte man f()
aufrufen und innerhalb von f
wäre etwas wie args = eval(formals(f), parent.frame())
, aber eingekapselt in ein makroähnliches Konstrukt args = get.args.by.name
oder ähnliches. Dies unterscheidet sich von Ihrer Idee darin, dass f
absichtlich programmiert werden muss, um diese Funktion zu haben.
Hier ist eine Antwort, die zunächst scheint zu funktionieren. Die Diagnose, warum dies nicht der Fall ist, kann zur Aufklärung führen, warum dies nicht möglich ist (Hinweis: siehe ersten Absatz von @crowdings Antwort ).
%Vor% Beide produzieren 1*2-3 == -1
, obwohl die Reihenfolge von b=2
und c=3
in der formalen Argumentliste von child1
gegen child2
ausgetauscht wurde.
Dies ist im Grunde eine Erklärung für Menels Antwort. Wenn es passiert, um Ihre Frage zu beantworten, bitte akzeptieren Sie es nicht oder verleihen Sie das Kopfgeld; es sollte nach Mnel gehen. Zuerst definieren wir call_as_parent
, mit dem Sie eine Funktion innerhalb einer anderen Funktion als externe Funktion aufrufen:
Dann definieren wir Eltern und Kind:
%Vor%Und schließlich einige Beispiele
%Vor% Beachten Sie, wie klar im zweiten Beispiel die 20 mit c
übereinstimmt, wie es sollte.