更新S3方法调用

时间:2015-12-22 09:55:00

标签: r call packages

我正在尝试更新我使用新类开发的新函数的调用。这种发展与Leish的文章"Creating R packages"中的linmod非常相似。

在函数内部,调用与match.call()一起存储。

当我尝试更新通话时,如下所示:

library(MASS)
fit <- linmod(Hwt~Bwt*Sex, data=cats)
update(fit, subset = -1)

我收到以下错误消息:

  

eval(expr,envir,enclos)中的错误:     找不到功能“linmod.formula”

问题似乎是match.call()保存了完整的S3方法名称(linmod.formula),而不仅仅是通用函数名称(linmod),它可以完美地运行。

任何人都可以帮我解决这个问题吗?

2 个答案:

答案 0 :(得分:0)

我知道修复此问题的最简单方法是导出方法。为此,您需要添加@export linmod.formula。当然,通常不建议导出方法。

另一种选择是为update创建方法。以下是update.default的副本,另外还有一行:

#' @export
update.linmod <- function (object, formula., ..., evaluate = TRUE) 
{
  if (is.null(call <- getCall(object))) 
    stop("need an object with call component")
  extras <- match.call(expand.dots = FALSE)$...
  #call generic instead of method:
  call[[1]] <- quote(linmod)
  if (!missing(formula.)) 
    call$formula <- update.formula(formula(object), formula.)
  if (length(extras)) {
    existing <- !is.na(match(names(extras), names(call)))
    for (a in names(extras)[existing]) call[[a]] <- extras[[a]]
    if (any(!existing)) {
      call <- c(as.list(call), extras[!existing])
      call <- as.call(call)
    }
  }
  if (evaluate) 
    eval(call, parent.frame())
  else call
}

我不喜欢这两个选项,并且会避免使用linmod函数的方法。你的默认方法对我来说似乎毫无用处。请注意,例如,lm不是S3泛型。

PS:update没有subset参数。

答案 1 :(得分:0)

由于这里还没有提到这一点,而且它是?update 中明确推荐的方法:为getCall 编写一个方法。来自?update

<块引用>

update() 和类似函数中的“提取调用”使用 getCall(),它本身是一个 (S3) 泛型函数,带有一个简单的获取 x$call 的默认方法。因此,update() 通常会在新模型类上工作(通过其默认方法),或者自动运行,或者通过为该类提供简单的 getCall() 方法。

因此,在您的包裹中,如果您有:

#' @export
f <- function(x) {
  UseMethod("f")
}

#' @export
f.bar <- function(x) {
  structure(list(x = x, call = match.call()), class = "fbar")
}

#' @export
#' @importFrom stats getCall
getCall.fbar <- function(x) {
  x$call[[1L]] <- quote(f) # replacing `f.bar`
  x$call
}

然后,在您的脚本中,您可以:

x1 <- structure(1, class = "bar")
x2 <- structure(2, class = "bar")

fx1 <- f(x = x1)
fx2 <- update(fx1, x = x2)

fx1
# $x
# [1] 1
# attr(,"class")
# [1] "bar"
#
# $call
# f.bar(x = x1)
#
# attr(,"class")
# [1] "fbar"

fx2
# $x
# [1] 2
# attr(,"class")
# [1] "bar"
# 
# $call
# f.bar(x = x2)
# 
# attr(,"class")
# [1] "fbar"