使用“...”和“复制”

19
sapplyreplicate的文档中,有一个关于使用...的警告。
现在,我可以接受这个警告,但是想要了解背后的原因。所以我创建了这个小的人为例子:
innerfunction<-function(x, extrapar1=0, extrapar2=extrapar1)
{
    cat("x:", x, ", xp1:", extrapar1, ", xp2:", extrapar2, "\n")
}

middlefunction<-function(x,...)
{
    innerfunction(x,...)
}

outerfunction<-function(x, ...)
{
    cat("Run middle function:\n")
    replicate(2, middlefunction(x,...))
    cat("Run inner function:\n")
    replicate(2, innerfunction(x,...))
}

outerfunction(1,2,3)
outerfunction(1,extrapar1=2,3)
outerfunction(1,extrapar1=2,extrapar2=3)

也许我犯了一些显而易见的错误,但是我发现这个结果相当令人沮丧。那么,有没有人可以解释一下为什么在调用outerfunction的所有上述情况中,我会得到这样的输出:

Run middle function:
x: 1 , xp1: 0 , xp2: 0 
x: 1 , xp1: 0 , xp2: 0 
Run inner function:
x: 1 , xp1: 0 , xp2: 0 
x: 1 , xp1: 0 , xp2: 0

就像我说的那样:文档似乎对此发出了警告,但我不明白为什么会这样。

4个回答

12

?replicate在示例部分明确告诉我们,您正尝试做的事情不起作用,也不会起作用。在?replicateNote部分中,我们有:

     If ‘expr’ is a function call, be aware of assumptions about where
     it is evaluated, and in particular what ‘...’ might refer to.  You
     can pass additional named arguments to a function call as
     additional named arguments to ‘replicate’: see ‘Examples’.

如果我们查看示例,会发现:

 ## use of replicate() with parameters:
 foo <- function(x=1, y=2) c(x,y)
 # does not work: bar <- function(n, ...) replicate(n, foo(...))
 bar <- function(n, x) replicate(n, foo(x=x))
 bar(5, x=3)

我的理解是文档不仅会警示你不要在replicate()函数中使用...,而且还明确文档说明这样做无效。该帮助文件中的大部分讨论都与其他函数的... 参数有关,而不一定与replicate()有关。


请注意,在此示例中,“正确”的方法也无法正常工作-它会被复制“x”次(3次)而不是“n”次(5次)。 - James
1
@James - 我的系统上没有这个问题。对于 bar(5, x = 3),我得到了一个2*5的矩阵。 - Gavin Simpson
翻译:哎呀,我的错误。在转录示例时打错了一个字母。 - James
1
@Gavin:?replicate中的引用是我在问题中提到的警告。我想知道的是这个警告的含义是什么?“where it is evaluated”和“what ... might refer to”对我来说有些神秘。所以,再次强调:我接受它不起作用,但是为什么不起作用?这可能会极大地帮助我/他人理解R中的参数传递/解析。 - Nick Sabbe
1
@Nick 对于晚回复表示抱歉;我认为这不起作用的原因是你没有在 expr 中调用该函数,而只是评估了 expr。由于没有调用它,因此从外部调用 ...expr 中就没有传递参数。这是一个微妙的区别,但非常重要;这就像在全局环境中完全像那样调用 middlefunction(...)(你不能这样做,因为R不允许你那样交互使用 ...),其中 ... 不指代任何内容。 - Gavin Simpson

6

如果您查看replicate的代码:

> replicate
function (n, expr, simplify = TRUE) 
sapply(integer(n), eval.parent(substitute(function(...) expr)), 
    simplify = simplify)
<environment: namespace:base>

您会发现该函数在父级框架中被评估,在那里您调用函数的...已不再存在。


1

实际上有一种方法可以做到这一点:

# Simple function:
ff <- function(a,b) print(a+b)

# This will NOT work:
testf <- function(...) {
  replicate(expr = ff(...), n = 5)
}
testf(45,56) # argument "b" is missing, with no default

# This will:
testf <- function(...) {
  args <- as.list(substitute(list(...)))[-1L]
  replicate(expr = do.call(ff, args), n = 5)
}
testf(45,56) # 101

0

另一种实现方式:

g <- function(x, y) x + y

f <- function(a = 1, ...) {
    arg_list <- list(...)
    replicate(n = 3, expr = do.call(g, args = arg_list))
}

f(x = 1, y = 2)

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