2015-07-22 14 views
10

ho imparato che è pratica comune utilizzare argomenti facoltativi in ​​funzione e controllare con mancanti() (ad esempio come discusso in SO 22024082)Passaggio argomento della funzione mancante di funzionare in R

In questo esempio round0 è l'argomento facoltativo (lo so, round0 potrebbe essere definito come logico).

Ma cosa succede se chiamo questa funzione da un'altra funzione, come posso passare "mancante"?

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

Se b < 10 poi round1 in bar() non è definito, ma è passato a foo comunque. Se modifico foo():

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

ed eseguire bar (9) l'output è:

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

Ciò significa: round0 non manca, ma non è possibile accedere sia?

Non voglio utilizzare diverse chiamate di funzione in bar(), se ci sono diversi argomenti opzionali in foo(), dovrei scrivere una chiamata di funzione per ogni mancante/non mancante - combinazione di tutti gli argomenti opzionali .

È possibile passare "mancante" o quale altra soluzione si applica a questo problema?

+0

In genere, se si chiama una funzione in un formato specifico, è necessario assicurarsi di disporre di tutti i parametri. Qui aggiungo un 'round1 = F' all'inizio di' bar' e aggiorno 'foo' con' if (! Missing (round0) && round0) '. Manca la possibilità di chiamare 'foo (a)' o 'foo (a, T/F)', se lo chiami con due parametri, il secondo parametro non manca e deve essere risolvibile. – Tensibai

+0

La mia ipotesi è che "missing" restituisca "FALSE" non appena l'oggetto promessa che rappresenta l'argomento della funzione ha uno slot di espressione non vuoto. Aggiungi la riga 'print (sostituto (round0))' subito dopo 'a = a * pi' nella tua funzione' foo' modificata e quindi esegui 'foo (9)'. 'sostituto' estrarrà lo slot di espressione. Non stamperà nulla, cioè uno slot di espressione vuota per 'round0'. Ora prova 'bar (9)'. Questo stampa 'round1'. Ma quando usi 'print', R proverà a valutare' round1' che non è stato ancora definito (valutazione lazy). – cryo111

risposta

7

Nel tuo esempio, round0 non è mancante, è impostato su round1 che non è definito (in contrapposizione a mancante).

Il modo migliore in generale di fare questo è quello di utilizzare un valore predefinito, nel tuo caso 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) 
} 

o in cui il valore di default non può essere facilmente espressa nella lista dei parametri:

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) 
} 

Nota in entrambi i casi è necessario impostare manualmente il parametro come valore predefinito nella funzione di chiamata.

Si potrebbe anche chiamare la funzione foo con o senza un argomento, se necessario, all'interno del vostro if dichiarazione:

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

Ma non si può (per quanto ne so) fare una variabile missing diverso da solo non passarlo come argomento.

1

Recentemente ho riscontrato un problema simile e volevo risolverlo in modo generale. Penso che possa essere fatto come indicato nella definizione della funzione g() di seguito:

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()) 
} 

Ecco cosa si ottiene quando si chiama g() con diverse serie di argomenti:

> 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 

È possibile aggiungere o rimuovere dalla lista args se non si desidera passare tutti gli argomenti alla funzione successiva o si desidera aggiungerne alcuni.A titolo di esempio, vedere la seguente funzione g() che fa questo in modo generale:

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()) 
} 

Ecco cosa si ottiene quando si chiama g() con diverse serie di argomenti:

> 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 

Vedi this answer per ulteriori informazioni su do.call().

Problemi correlati