【问题标题】:Behavior of do.call() in the presence of arguments without defaults存在没有默认值的参数时 do.call() 的行为
【发布时间】:2013-08-09 03:02:25
【问题描述】:

这个问题是previous answer 的后续问题,它提出了一个难题。

上一个答案的可重现示例:

Models <- list( lm(runif(10)~rnorm(10)),lm(runif(10)~rnorm(10)),lm(runif(10)~rnorm(10)) )
lm1 <- lm(runif(10)~rnorm(10))
library(functional)
# This works
do.call( Curry(anova, object=lm1), Models )
# But so does this
do.call( anova, Models )

问题是为什么do.call(anova, Models) 工作正常,正如@Roland 指出的那样?

anova 的签名是anova(object, ...)

anova 调用UseMethod,它应该* 调用anova.lm,它应该调用anova.lmlist,其第一行是objects &lt;- list(object, ...),但object 在该公式中不存在。

我唯一可以推测的是do.call 可能不只是填写省略号,而是填写所有没有默认值的参数,并为省略号留下任何额外信息?如果是这样,那记录在哪里,因为它对我来说绝对是新的!

* 这本身就是一个线索——如果第一个参数未指定,UseMethod 如何知道调用anova.lm?没有anova.list 方法或anova.default 或类似方法...

【问题讨论】:

  • 不是和do.call(plot, list(1:2, 1:2, col="red"))一样的情况吗?它似乎遵循位置匹配、命名参数和... 的标准行为。
  • 我很困惑,do.call(anova, Models)anova(Models[[1]], Models[[2]], Models[[3]]) 相同有什么令人困惑的?
  • 因为do.call总是被说成是...的解决方案,所以我猜从来没有提到它也会根据位置匹配规则进行填充。但这让我很惊讶。
  • @SimonO101 似乎你错过了“*”的点,再次回滚......
  • do.call 只是从do.call(f, list(...))f(...) 进行基本的词法替换 - 您始终可以将命名和未命名参数传递给...

标签: r arguments do.call


【解决方案1】:

在常规函数调用中,... 按位置、部分匹配和完全匹配捕获参数:

f <- function(...) g(...)
g <- function(x, y, zabc) c(x = x, y = y, zabc = zabc)

f(1, 2, 3)
# x    y zabc 
# 1    2    3     
f(z = 3, y = 2, 1)
# x    y zabc 
# 1    2    3     

do.call 的行为方式完全相同,只不过不是将参数直接提供给函数,而是将它们存储在一个列表中,do.call 负责将它们传递给函数:

do.call(f, list(1, 2, 3))
# x    y zabc 
# 1    2    3     
do.call(f, list(z = 3, y = 2, 1))
# x    y zabc 
# 1    2    3     

【讨论】:

    【解决方案2】:

    我认为值得强调的是列表元素的名称很重要。哈德利提到了它,但这可能是一个烦恼。考虑下一个例子:

    x <- rnorm(1000)
    y <- rnorm(1000)
    z <- rnorm(1000) + 0.2
    
    Models <- list()
    Models$xy <- lm(z~x)
    Models$yz <- lm(z~y)
    
    # This will fail, because do.call will not assign anything to the argument "object" of anova
    do.call(anova, Models)
    # This won't
    do.call(anova, unname(Models))
    

    【讨论】:

      【解决方案3】:

      do.call 将列表的第一个元素传递给第一个参数:

      fun <- function(x,...) {
        print(paste0("x=",x))
      
        list(x, ...)
      }
      
      do.call(fun, list(1,2))
      # [1] "x=1"
      # [[1]]
      # [1] 1
      # 
      # [[2]]
      # [1] 2
      

      【讨论】:

      • 它还能做什么?! do.call(f, list(1,2)) 的定义不应该等同于f(1,2) 吗?我真的没有得到 OP。
      • 好吧,我们认为f &lt;- function(...) 会是这种情况,但f &lt;- function(x ,...) 不会。我希望后者会给do.call 一个错误。
      • @eddi 我只能用... 代替,否则返回错误。它的实际工作方式显然更有用,但最常见的用法是填写...
      • :) 不知道你为什么会这么想,但没关系
      • 我们错了,但认为 do.call 只会填充省略号对我来说似乎并不牵强,尽管文档的示例部分显示并非如此。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-07-05
      • 1970-01-01
      • 2016-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多