2014-09-22 10 views
6

Per il momento, almeno, questo è un esercizio di apprendimento per me, quindi le funzioni effettive o la loro complessità non sono il problema. Supponiamo di scrivere una funzione il cui elenco di argomenti include alcune variabili di input e un nome di funzione, passati come una stringa. Questa funzione calcola alcune variabili internamente e "decide" come inviarle al nome della funzione che ho passato.Come recuperare le formali di una funzione primitiva?

Per le funzioni non primitive, posso fare (per questo esempio, supponiamo che le mie funzioni funcname abbiano argomenti . diversa al massimo (x,y,z) Se lo facessero, avrei dovuto scrivere del codice per la ricerca per la corrispondenza names(formals(get(funcname))) in modo da non eliminare gli altri argomenti):

foo <- function (a,b,funcname) { 
    x <- 2*a 
    y <- a+3*b 
    z <- -b 
    formals(get(funcname)) <- list(x=x, y=y, z=z) 
    bar <- get(funcname)() 
return(bar) 
} 

e la cosa bella è, anche se la funzione funcname verrà eseguito senza errori anche se non utilizza x, o z (a patto che non ci sono altri argomenti che non hanno valori predefiniti).
Il problema con le funzioni "primitive" è che non conosco alcun modo per trovare o modificare le loro formali. Altro che scrivere un wrapper, ad es. foosin <-function(x) sin(x), c'è un modo per impostare la mia funzione foo per lavorare con nomi di funzioni sia primitive che non primitive come argomenti di input?

+2

Qualcuno recentemente suggerito che uso 'formali (args (FUN)) 'per ottenere le formali di un primitivo. –

risposta

3

formals(args(FUN)) può essere utilizzato per ottenere le formali di una funzione primitiva.

È possibile aggiungere un'istruzione if alla funzione esistente.

> formals(sum) 
# NULL 
> foo2 <- function(x) { 
     if(is.primitive(x)) formals(args(x)) else formals(x) 
     ## formals(if(is.primitive(x)) args(x) else x) is another option 
    } 
> foo2(sum) 
# $... 
# 
# 
# $na.rm 
# [1] FALSE 
# 
> foo2(with) 
# $data 
# 
# 
# $expr 
# 
# 
# $... 
+0

In realtà, 'formals (args (non_primitive_func))' restituisce la stessa cosa di solo 'formals (non_primitive_func)'. Ma non pensavo a quella cosa del raddoppio. Grazie! –

+0

Giusto, ma senza 'args' non otterrebbe mai le formali del primitivo. Sono sicuro che potremmo regolarlo per non ripetere 'formals' nel codice. Aggiornamento –

+0

: sfortunatamente questa è solo metà della battaglia. Non riesco ancora a ridefinire le formali di un Primitive nel modo in cui le ho ridefinite per la mia funzione di esempio. Il meglio che riesco a pensare finora (per i Primitivi) è di verificare quale di 'x, y, z' esista nella funzione corrente' funcname' e costruisca un 'do.call' con quella sottolista. –

1

Sulla base della risposta di Richard S, ho finito per fare quanto segue. Inserito nel caso in cui qualcun altro abbia mai provato a fare cose strane come me.

MODIFICA: Penso che sia necessario eseguire ulteriori controlli di tipo. È possibile che possa essere il nome di un oggetto, nel qual caso get(coleqn) restituirà alcuni dati. Probabilmente ho bisogno di per aggiungere uno if(is.function(rab)) subito dopo lo if(!is.null(rab)). (Naturalmente, dato che ho scritto la funzione per i miei bisogni, se sono stato abbastanza stupido da passare un oggetto, mi merito quello che ottengo :-)).

# "coleqn" is the input argument, which is a string that could be either a function 
# name or an expression. 

rab<-tryCatch(get(coleqn),error=function(x) {}) 
#oops, rab can easily be neither NULL nor a closure. Damn. 
if(!is.null(rab)) { 
# I believe this means it must be a function 
# thanks to Richard Scriven of SO for this fix to handle primitives 
# we are not allowed to redefine primitive's formals. 
    qq <- list(x=x,y=y,z=z) 
# matchup the actual formals names 
# by building a list of valid arguments to pass to do.call 
    argk<-NULL 
    argnames<-names(formals(args(coleqn))) 
    for(j in 1:length(argnames)) 
     argk[j]<-which(names(qq)==argnames[1]) 
    arglist<-list() 
    for(j in 1:length(qq)) 
     if(!is.na(argk[j])) arglist[[names(qq)[j]]]<-qq[[j]] 
    colvar<- do.call(coleqn,arglist) 
    } else { 
# the input is just an expression (string), not a function 
     colvar <- eval(parse(text=coleqn)) 
    } 

Il risultato è un oggetto generato mediante l'espressione o la funzione appena creata, utilizzando variabili interne alla funzione principale (non mostrato in questo frammento)

+0

Faccio cose strane tutto il tempo http://stackoverflow.com/questions/25376197/split-up-arguments-and-distribute-to-multiple-functions –

Problemi correlati