如何为未评估的赋值表达式定义 S3 方法?
How can I define an S3 method for an unevaluated assignment expression?
tl;dr: R CMD check
complains when I implement a generic for the S3 class <-
, because it thinks that the function is a replacement function with incorrect arguments.
我需要定义一组 S3 泛型来遍历未计算的 R 表达式的 AST。
出于演示目的,请考虑以下 S3 泛型及其方法:
walk = function (x) UseMethod('walk')
walk.default = function (x) message('default')
walk.name = function (x) message('name')
walk.call = function (x) message('call')
这很好用:
tests = alist('2', c, f(1))
invisible(lapply(tests, walk))
default
name
call
但是,有不少调用表达式的S3class不是call
;例如:
tests2 = alist(for (x in y) ., if (.) ., x <- .)
invisible(lapply(tests2, walk))
default
default
default
……哎呀。我希望 将这些表达式视为调用。我可以通过添加更多方法来做到这一点:
walk.for = function (x) message('for')
walk.if = function (x) message('if')
`walk.<-` = function (x) message('<-')
# … and so on for other syntax constructs.
现在我在调用 walk
时得到了预期的结果:
for
if
<-
然而,这段代码是一个包的一部分,R CMD check
抱怨walk.<-
的定义,因为它认为该函数是一个替换函数:
W checking replacement functions ...
‘walk.<-’
The argument of a replacement function which corresponds to the right
hand side must be named ‘value’.
而且我明白 为什么 我会收到警告(事实上,这看起来像是为 walk.
定义替换函数的拙劣尝试)。但是当然这个 不是 替换函数,所以警告是误报。那么我应该如何明确地为 class <-
实现 S3 泛型呢?或者这是 R CMD check
中的错误?我可以摆脱警告吗?我无法向函数添加额外的参数。
Writing R Extensions, section 1.5.2 Registering S3 methods提供了一个变通方案:
It is possible to specify a third argument to S3method
, the function to be used as the method, for example
S3method(print, check_so_symbols, .print.via.format)
when print.check_so_symbols
is not needed.
这意味着,我们不定义 `walk.<-`
,而是执行以下操作:
R/‹some-file›.r
中的实施:
walk_assign = function (x) message('<-')
(与其他 S3 方法不同,函数名称并不重要。)
NAMESPACE
声明:
S3method(walk, '<-', walk_assign)
这与在常规 R 脚本中调用 .S3method('walk', '<-', \(x) message('<-'))
的效果相同。有趣的是,.S3method()
also 似乎在包内工作(而不是上面基于 NAMESPACE
的解决方案),但函数的文档说不要在包中使用它所以这可能会在未来崩溃。
当然,正如 Allan Cameron 评论的那样,一个可以说更简单的解决方案是将 <-
案例与 default
融合,并在 walk.default
中使用 if
来消除歧义:
walk.default = function (x) {
if (inherits(x, '<-')) {
message('<-')
} else {
message('default')
}
}
但是,我个人不喜欢将 S3 调度与 if
混合使用。
tl;dr:
R CMD check
complains when I implement a generic for the S3 class<-
, because it thinks that the function is a replacement function with incorrect arguments.
我需要定义一组 S3 泛型来遍历未计算的 R 表达式的 AST。
出于演示目的,请考虑以下 S3 泛型及其方法:
walk = function (x) UseMethod('walk')
walk.default = function (x) message('default')
walk.name = function (x) message('name')
walk.call = function (x) message('call')
这很好用:
tests = alist('2', c, f(1))
invisible(lapply(tests, walk))
default
name
call
但是,有不少调用表达式的S3class不是call
;例如:
tests2 = alist(for (x in y) ., if (.) ., x <- .)
invisible(lapply(tests2, walk))
default
default
default
……哎呀。我希望 将这些表达式视为调用。我可以通过添加更多方法来做到这一点:
walk.for = function (x) message('for')
walk.if = function (x) message('if')
`walk.<-` = function (x) message('<-')
# … and so on for other syntax constructs.
现在我在调用 walk
时得到了预期的结果:
for
if
<-
然而,这段代码是一个包的一部分,R CMD check
抱怨walk.<-
的定义,因为它认为该函数是一个替换函数:
W checking replacement functions ... ‘walk.<-’ The argument of a replacement function which corresponds to the right hand side must be named ‘value’.
而且我明白 为什么 我会收到警告(事实上,这看起来像是为 walk.
定义替换函数的拙劣尝试)。但是当然这个 不是 替换函数,所以警告是误报。那么我应该如何明确地为 class <-
实现 S3 泛型呢?或者这是 R CMD check
中的错误?我可以摆脱警告吗?我无法向函数添加额外的参数。
Writing R Extensions, section 1.5.2 Registering S3 methods提供了一个变通方案:
It is possible to specify a third argument to
S3method
, the function to be used as the method, for exampleS3method(print, check_so_symbols, .print.via.format)
when
print.check_so_symbols
is not needed.
这意味着,我们不定义 `walk.<-`
,而是执行以下操作:
R/‹some-file›.r
中的实施:
walk_assign = function (x) message('<-')
(与其他 S3 方法不同,函数名称并不重要。)
NAMESPACE
声明:
S3method(walk, '<-', walk_assign)
这与在常规 R 脚本中调用 .S3method('walk', '<-', \(x) message('<-'))
的效果相同。有趣的是,.S3method()
also 似乎在包内工作(而不是上面基于 NAMESPACE
的解决方案),但函数的文档说不要在包中使用它所以这可能会在未来崩溃。
当然,正如 Allan Cameron 评论的那样,一个可以说更简单的解决方案是将 <-
案例与 default
融合,并在 walk.default
中使用 if
来消除歧义:
walk.default = function (x) {
if (inherits(x, '<-')) {
message('<-')
} else {
message('default')
}
}
但是,我个人不喜欢将 S3 调度与 if
混合使用。