函数执行期间显示实际参数列表

4
我想显示函数调用时提供的参数的实际值。`match.call'可以做到类似的事情,但它不会评估变量。例如:
foo <- function(x) match.call()
foo(2)

打印

foo(x = 2)

我对此感到满意。然而:


xxx <- 2
foo(xxx)

将会打印

foo(x = xxx)

我希望使用x = 2作为参数,而不是foo(x = 2)

我尝试了各种substituteeval和其他方法,但都没有成功。

2个回答

7

我之前写了一个函数expand.call(),它可以做你想要的事情(我认为...)。实际上,它可以做更多的事情:

#' 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])))
}

如果您需要保留有关调用的更多信息或将其格式化得更好,通常会将此用作match.call()的替代方法:

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)

也许您可以使用它来解决您的问题。

1
这是一个很棒的函数!不过我认为缺少了形式参数 eval。如果我可以提出建议:也许您可以考虑将该参数命名为 doEval,以免与函数 eval 引起混淆。 - BenBarnes
谢谢@BenBarnes。我已经按照你的建议进行了更改。 - fabians
使用 apply 来执行 eval 会破坏搜索路径。如果您已经定义了变量 c,则将被评估为 c 原始函数。最好使用 for 循环。 - ThomasP85
@ThomasP85 谢谢,我按照你的建议进行了更改。 - fabians

3

我不确定这是否是最佳方法,但可能可以通过以下方式实现:

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)

哦,棘手!它解决了直接在 match.call() 上使用 eval 会再次调用函数的问题。谢谢! - Aniko

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接