Weitere Einblicke in die Geheimnisse der R-Bewertung ... Dies ist eng verwandt mit meiner vorherigen Frage (How to write an R function that evaluates an expression within a data-frame). Nehmen wir an, ich möchte eine Funktion topfn
schreiben, die einen Datenrahmen und einen Ausdruck mit Spaltennamen dieses Datenrahmens annimmt. Ich möchte diese beiden Argumente an eine andere Funktion übergeben fn
, die tatsächlich den Ausdruck innerhalb der "Umgebung" des Datenrahmens auswertet. Und ich will beide fn
und topfn
korrekt arbeiten, wenn ein Datenrahmen und einen Ausdruck übergebenR: Ausdruck an eine innere Funktion übergeben
Mein erster Versuch, wie in der Antwort auf die obige Frage vorgeschlagen, ist zu definieren:
fn <- function(dfr, expr) {
mf <- match.call()
eval(mf$expr, envir = dfr)
}
und definieren topfn
wie folgt aus:
topfn <- function(df, ex) {
mf <- match.call()
fn(df, mf$ex)
}
wenn ich nun ein Datenrahmen
habendf <- data.frame(a = 1:5, b = 1:5)
die innere Funktion fn
gut funktioniert:
> fn(df,a)
[1] 1 2 3 4 5
Aber die topfn
funktioniert nicht:
> topfn(df,a)
mf$ex
dies zu beheben ich zuerst die Klasse von topfn(df,a)
überprüfen,
> class(topfn(df,a))
[1] "call"
Das gibt mir eine Idee für einen hässlichen Hack, umneu zu definierenwie folgt:
fn <- function(dfr, expr) {
mf <- match.call()
res <- eval(mf$expr, envir = dfr)
if(class(res) == 'call')
eval(expr, envir = dfr) else
res
}
Und nun beide Funktionen arbeiten:
> fn(df,a)
[1] 1 2 3 4 5
> topfn(df,a)
[1] 1 2 3 4 5
Wie gesagt, das ist wie eine hässliche Hack aussieht. Gibt es einen besseren Weg (oder mehr Standard-Idiom), um diese funktionieren zu lassen? Ich habe Lumleys seltsamerweise benannte Standard NonStandard Evaluation Rules Dokument http://developer.r-project.org/nonstandard-eval.pdf konsultiert, aber war nicht besonders erleuchtet nach dem Lesen. Hilfreich wären auch Hinweise auf Quellcodes von Funktionen, die ich für Beispiele betrachten kann.
Es gibt ein großes Wiki zum Thema R Auswertung von Hadley Wickham hier: https: //github.com/hadley/devtools/wiki/Evaluation –
Und wie ich Ihnen vorschlage, möchten Sie sorgfältig zwischen Funktionen unterscheiden, die interaktiv verwendet werden, und das funktioniert werden von anderen Funktionen aufgerufen. Es ist sehr schwierig, eine Funktion aufzurufen, die Ersatz- und andere Tricks verwendet. Mit anderen Worten, es gibt keinen sauberen Weg für "fn" und "topfn", um mit den gleichen Arten von Eingaben zu arbeiten - und das ist eine GUTE Sache. – hadley
@hadley Ich sehe Ihren Punkt: Funktionen für die interaktive Verwendung können Ersatz/andere Tricks verwenden, um es einfach zu machen, sie an der Konsole (d. H. Keine Anführungszeichen, usw.) einzugeben. Und Funktionen, die nur dazu bestimmt sind, von anderen Funktionen aufgerufen zu werden, sollten solche Tricks nicht verwenden, da sie unvorhersehbar brechen können. Insbesondere die Lösung von @Richie am Ende seiner Antwort, obwohl es in meinem speziellen Szenario oben funktioniert - es kann brechen (vor allem "fn"), wenn in einem anderen Szenario verwendet - ich denke, das ist, was Sie " sag ich, oder? –