2010-08-13 23 views
4

J'essaie d'afficher les valeurs réelles des paramètres fournis lors de l'appel de la fonction. `match.call 'fait quelque chose le long des lignes que je veux, mais il n'évalue pas les variables. Par exempleAffichage de la liste des paramètres réels de la fonction pendant l'exécution

foo <- function(x) match.call() 
foo(2) 

impressions

foo(x = 2) 

et je suis heureux. Cependant:

xxx <- 2 
foo(xxx) 

imprimera

foo(x = xxx) 

au lieu de foo(x = 2) que je voudrais avoir.

J'ai essayé différentes combinaisons de substitute, eval, et de la compagnie, mais n'a pas été couronnée de succès.

Répondre

3

Je ne sais pas si cela est la meilleure façon, mais probablement vous pouvez le faire par:

x<-"a" 
y<-mean 
z<-1 
foo <- function(x,y,z) { 
    do.call("call", 
      c(list(as.character(match.call()[[1]])), 
      lapply(as.list(match.call())[-1],eval))) 
} 
foo(x,y,z) 
+0

Oooh, difficile! Il résout le problème que l'utilisation de 'eval' sur' match.call() 'ne fera qu'appeler directement la fonction. Merci! – Aniko

7

J'ai écrit un expand.call() fonction qui fait ce que vous voulez (je pense .. .) il y a un moment. En fait, il fait un peu plus:

#' Return a call in which all of the arguments which were supplied 
#' or have presets are specified by their full names and supplied 
#' or default values. 
#' 
#' @param definition a function. See \code{\link[base]{match.call}}. 
#' @param call an unevaluated call to the function specified by definition. 
#' See \code{\link[base]{match.call}}. 
#' @param expand.dots logical. Should arguments matching ... in the call be 
#' included or left as a ... argument? See \code{\link[base]{match.call}}. 
#' @param doEval logical, defaults to TRUE. Should function arguments be 
#' evaluated in the returned call or not? 
#' 
#' @return An object of class call. 
#' @author fabians 
#' @seealso \code{\link[base]{match.call}} 
expand.call <- function(definition=NULL, 
     call=sys.call(sys.parent(1)), 
     expand.dots = TRUE, 
     doEval=TRUE) 
{ 

    safeDeparse <- function(expr){ 
     #rm line breaks, whitespace    
     ret <- paste(deparse(expr), collapse="") 
     return(gsub("[[:space:]][[:space:]]+", " ", ret)) 
    } 

    call <- .Internal(match.call(definition, call, expand.dots)) 

    #supplied args: 
    ans <- as.list(call) 
    if(doEval & length(ans) > 1) { 
     for(i in 2:length(ans)) ans[[i]] <- eval(ans[[i]]) 
    } 

    #possible args: 
    frmls <- formals(safeDeparse(ans[[1]])) 
    #remove formal args with no presets: 
    frmls <- frmls[!sapply(frmls, is.symbol)] 

    add <- which(!(names(frmls) %in% names(ans))) 
    return(as.call(c(ans, frmls[add]))) 
} 

Vous devriez normalement utiliser comme un substitut à match.call() si vous avez besoin de conserver une certaine plus d'informations sur l'appel ou avoir formaté plus bien, comme:

foo <- function(x, bar="bar", gnurp=10, ...) { 
    call <- expand.call(...) 
    return(call) 
} 

> foo(2) 
foo(x = 2, bar = "bar", gnurp = 10) 

> xxx <- 2 
> foo(xxx) 
foo(x = 2, bar = "bar", gnurp = 10) 

> foo(xxx, b="bbbb") 
foo(x = 2, bar = "bbbb", gnurp = 10) 

> foo(xxx, b="bbbb", doEval=FALSE) 
foo(x = xxx, bar = "bbbb", doEval = FALSE, gnurp = 10) 

Peut-être que vous pouvez l'utiliser pour résoudre votre problème.

+1

C'est une super fonction! Je pense que l'argument formel 'eval' est manquant, cependant. Si je peux ajouter une suggestion: peut-être que vous envisageriez de nommer cet argument 'doEval' pour ne pas créer de confusion avec la fonction' eval'. – BenBarnes

+0

Merci, @BenBarnes. J'ai fait les changements que vous avez suggérés. – fabians

+0

L'utilisation de apply pour l'eval salit le chemin de recherche. Si vous avez défini une variable c, elle sera évaluée par rapport à la fonction primitive c. Mieux vaut utiliser une boucle for. – ThomasP85