2015-07-22 25 views
10

Ich habe gelernt, dass es gängige Praxis ist optionale Argumente in der Funktion zu verwenden und überprüfen Sie sie mit fehlenden() (zB wie in SO 22024082 diskutiert)Passing Argument Funktion fehlt in R funktionieren

In diesem Beispiel round0 ist das optionale Argument (Ich weiß, dass round0 als logisch definiert werden könnte).

foo = function(a, round0) { 
    a = a * pi 
    if(!missing(round0)) round(a) 
    else a 
} 

Aber was, wenn ich diese Funktion von einer anderen Funktion aus rufe, wie kann ich "missing" übergeben?

bar = function(b) { 
    if(b > 10) round1=T 
    foo(b, round1) 
} 

Wenn b < 10 dann Round1 in bar() nicht definiert ist, wird aber trotzdem weitergegeben foo. Wenn ich ändern foo():

foo = function(a, round0) { 
    a = a * pi 
    print(missing(round0)) 
    print(round0) 
    if(!missing(round0)) round(a) 
    else a 
} 

und Laufschiene (9) ist der Ausgang:

bar(9) 
[1] FALSE 
Error in print(round0) : object 'round1' not found 
Called from: print(round0) 

Das heißt: round0 nicht fehlt, kann aber auch nicht zugegriffen werden?

Ich möchte nicht verschiedene Funktionsaufrufe in bar() verwenden, wenn es mehrere optionale Argumente in foo() gibt, müsste ich einen Funktionsaufruf für jede fehlende/fehlende - Kombination aller optionalen Argumente schreiben .

Ist es möglich, "missing" zu übergeben, oder welche andere Lösung würde für dieses Problem gelten?

+0

Normalerweise, wenn Sie eine Funktion in einer bestimmten Form aufrufen, sollten Sie sicherstellen, dass Sie alle Parameter haben. Hier würde ich ein 'round1 = F' am Anfang von' bar' hinzufügen und 'foo' mit' if (! Missing (round0) && round0) 'aktualisieren. Missing erlaubt es Ihnen, 'foo (a)' oder 'foo (a, T/F)' aufzurufen, wenn Sie es mit zwei Parametern aufrufen, der zweite Parameter fehlt nicht und muss auflösbar sein. – Tensibai

+0

Meine Vermutung ist, dass "fehlende" 'FALSE' zurückgibt, sobald das Versprechen-Objekt, das das Funktionsargument darstellt, einen nicht leeren Ausdruck-Slot hat. Fügen Sie die Zeile 'print (substitute (round0))' direkt nach 'a = a * pi' in Ihrer modifizierten 'foo'-Funktion hinzu und führen Sie dann' foo (9) 'aus. 'substitute' extrahiert den Ausdrucksslot. Es wird nichts gedruckt, d. H. Ein leerer Ausdruck-Slot für 'Runde0'. Versuche jetzt 'bar (9) '. Dies druckt 'Runde1'. Aber wenn Sie 'print' verwenden, wird R versuchen,' round1' auszuwerten, was noch nicht definiert wurde (faule Auswertung). – cryo111

Antwort

7

In Ihrem Beispiel fehlt round0, es ist auf round1 eingestellt, was nicht definiert ist (im Gegensatz zu fehlenden).

Der beste Weg, in der Regel dabei ist, einen Standardwert zu verwenden, in Ihrem Fall FALSE:

foo = function(a, round0 = FALSE) { 
    a = a * pi 
    if (!round0) round(a) 
    else a 
} 

bar = function(b) { 
    round1 <- FALSE 
    if (b > 10) round1=TRUE 
    foo(b, round1) 
} 

oder wo der Standardwert nicht leicht in der Parameterliste ausgedrückt werden kann:

foo = function(a, round0 = NULL) { 
    a = a * pi 
    if(!is.null(round0)) round(a) 
    else a 
} 

bar = function(b) { 
    round1 <- NULL 
    if (b > 10) round1=TRUE 
    foo(b, round1) 
} 

Hinweis: In beiden Fällen müssen Sie den Parameter manuell in Ihrer aufrufenden Funktion als Standardwert festlegen.

Sie können auch Ihre foo Funktion mit oder ohne Argument aufrufen, wenn in Ihrer if Anweisung benötigt:

bar = function(b) { 
    if (b > 10) foo(b, TRUE) else foo(b) 
} 

Aber man kann nicht (soweit ich weiß) eine variable missing andere machen, als nur durch nicht als Argument übergeben.

1

Ich bin kürzlich auf ein ähnliches Problem gestoßen und wollte es allgemein lösen. Ich denke, es kann, wie in der Definition der Funktion g() unten erfolgen:

f <- function(a = 5, b = 3, c = 2, d = 7) { 
    if (missing(a)) {print("a is missing.")} 
    if (missing(b)) {print("b is missing.")} 
    if (missing(c)) {print("c is missing.")} 
    if (missing(d)) {print("d is missing.")} 

    cat(a, b, c, d) 
} 

g <- function(a = 1, b = 1, c = 1, d = 1) { 
    args <- as.list(match.call()) 
    args[[1]] <- NULL # remove first list element, it's the function call 
    do.call(f, args, envir = parent.frame()) 
} 

Hier ist, was wir bekommen, wenn g() mit verschiedenen Gruppen von Argumenten aufrufen:

> g() 
[1] "a is missing." 
[1] "b is missing." 
[1] "c is missing." 
[1] "d is missing." 
5 3 2 7 

> g(a = 3) 
[1] "b is missing." 
[1] "c is missing." 
[1] "d is missing." 
3 3 2 7 

> g(b = 10, c = 10) 
[1] "a is missing." 
[1] "d is missing." 
5 10 10 7 

Sie können hinzufügen oder Entfernen Sie aus der Liste args, wenn Sie nicht alle Argumente an die nächste Funktion übergeben möchten oder einige hinzufügen möchten.Als Beispiel die folgende Funktion sehen g(), das dies tut in allgemeiner Form:

g <- function(a = 1, b = 1, c = 1, x = 1, y = 1, z = 1) { 
    f_args <- c("a", "b", "c") # arguments we want to hand off to function f 

    # obtain the list of arguments provided 
    args <- as.list(match.call()) 
    # remove first list element, it's the function call 
    args[[1]] <- NULL 
    # remove the arguments that are not listed in f_args 
    args <- args[na.omit(match(f_args, names(args)))] 

    # now add argument d, we always want it to be 0: 
    args <- c(args, list(d = 0)) 
    do.call(f, args, envir = parent.frame()) 
} 

Hier ist, was bekommen wir, wenn g() mit verschiedenen Sätzen von Argumenten aufrufen:

> g() 
[1] "a is missing." 
[1] "b is missing." 
[1] "c is missing." 
5 3 2 0 

> g(a = 3) 
[1] "b is missing." 
[1] "c is missing." 
3 3 2 0 

> g(b = 10, c = 10) 
[1] "a is missing." 
5 10 10 0 

Siehe this answer für weitere Informationen auf do.call().