Rap*_*ter 11 r argument-passing dispatch s4
是否可以为一组包含 ...(而不是专门用于...)的签名参数定义方法?这是不可能的"开箱即用",但理论上它是否可能(涉及一些调整)或者由于S4机制的设计方式,这是不能完成的事情?
我正在寻找一些类似的东西
setGeneric(
name = "foo",
signature = c("x", "..."),
def = function(x, ...) standardGeneric("foo")
)
setMethod(
f = "foo",
signature = signature(x = "character", "..." = "ThreedotsRelevantForMe"),
definition = function(x, ...) bar(x = x)
)
Run Code Online (Sandbox Code Playgroud)
谢天谢地,马丁摩根指出了我dotsMethods,它说:
目前,"..."不能与其他形式参数混合:通用函数的签名只是"...",或者它不包含"......".(此限制可能会在将来的版本中解除.)
考虑以下尝试来概括基于...简单情况的调度机制(只有一个函数应该使用传递的参数...;例如使用...in plot()来传递参数par())到涉及以下方面的场景(取自此处):
r,接收者,c 调用堆栈的不同层上时另请注意,尽管这样做确实是一种好习惯,但顶级函数/接口不一定需要关注定义后续调用的函数/接口的(大量)显式参数,以便正确传递参数.IMO,这个选择应留给开发人员,因为有时一个或另一个选择更有意义.
如果我可以用S4调度员以某种方式替换当前通过withThreedots()(其中AFAICT需要涉及实际拆分...)的调度来替换那将是很酷的,因此理想情况下只需要调用foo(x = x, ...)而不是withThreedots("foo", x = x, ...)在foobar():
withThreedots <- function(fun, ...) {
threedots <- list(...)
idx <- which(names(threedots) %in% sprintf("args_%s", fun))
eval(substitute(
do.call(FUN, c(THREE_THIS, THREE_REST)),
list(
FUN = as.name(fun),
THREE_THIS = if (length(idx)) threedots[[idx]],
THREE_REST = if (length(idx)) threedots[-idx] else threedots
)
))
}
foobar <- function(x, ...) {
withThreedots("foo", x = x, ...)
}
foo <- function(x = x, y = "some text", ...) {
message("foo/y")
print(y)
withThreedots("bar", x = x, ...)
}
bar <- function(x = x, y = 1, ...) {
message("bar/y")
print(y)
withThreedots("downTheLine", x = x, ...)
}
downTheLine <- function(x = x, y = list(), ...) {
message("downTheLine/y")
print(y)
}
Run Code Online (Sandbox Code Playgroud)
foobar(x = 10)
foobar(x = 10, args_foo = list(y = "hello world!"))
foobar(x = 10, args_bar = list(y = 10))
foobar(x = 10, args_downTheLine = list(y = list(a = TRUE)))
foobar(x = 10,
args_foo = list(y = "hello world!"),
args_bar = list(y = 10),
args_downTheLine = list(y = list(a = TRUE))
)
# foo/y
# [1] "hello world!"
# bar/y
# [1] 10
# downTheLine/y
# $a
# [1] TRUE
Run Code Online (Sandbox Code Playgroud)
我想我正在寻找类似的东西:
定义
setGeneric(
name = "foobar",
signature = c("x"),
def = function(x, ...) standardGeneric("foobar")
)
setMethod(
f = "foobar",
signature = signature(x = "ANY"),
definition = function(x, ...) pkg.foo::foo(x = x, ...)
)
Run Code Online (Sandbox Code Playgroud)
假设:foo()在包/命名空间中定义pkg.foo
setGeneric(
name = "foo",
signature = c("x", "y", "..."),
def = function(x, y = "some text", ...) standardGeneric("foo")
)
setMethod(
f = "foo",
signature = signature(x = "ANY", y = "character", "..." = "Threedots.pkg.foo.foo"),
definition = function(x, y, ...) {
message("foo/y")
print(y)
pkg.bar::bar(x = x, ...)
}
)
Run Code Online (Sandbox Code Playgroud)
假设:bar()在包/命名空间中定义pkg.bar:
setGeneric(
name = "bar",
signature = c("x", "y", "..."),
def = function(x, y = 1, ...) standardGeneric("bar")
)
setMethod(
f = "bar",
signature = signature(x = "ANY", y = "numeric", "..." = "Threedots.pkg.bar.bar"),
definition = function(x, y, ...) {
message("bar/y")
print(y)
pkg.a::downTheLine(x = x, ...)
)
setGeneric(
name = "downTheLine",
signature = c("x", "y", "..."),
def = function(x, y = list(), ...) standardGeneric("downTheLine")
)
Run Code Online (Sandbox Code Playgroud)
假设:downTheLine()在包/命名空间中定义pkg.a:
setMethod(
f = "downTheLine",
signature = signature(x = "ANY", y = "list", "..." = "Threedots.pkg.a.downTheLine"),
definition = function(x, y, ...) {
message("downTheLine/y")
print(y)
return(TRUE)
)
Run Code Online (Sandbox Code Playgroud)
说明调度员需要做什么
关键部分是它必须能够区分那些...与被调用的相应当前 相关的元素fun(基于对常规 和 三脚签名参数的完整S4调度)以及应该传递给函数的那些元素.这fun可能会调用(即,更新状态...,类似于发生了什么内部withThreedots()以上):
s4Dispatcher <- function(fun, ...) {
threedots <- splitThreedots(list(...))
## --> automatically split `...`:
## 1) into those arguments that are part of the signature list of `fun`
## 2) remaining part: everything that is not part of
## the signature list and that should thus be passed further along as an
## updated version of the original `...`
args_this <- threedots$this
## --> actual argument set relevant for the actual call to `fun`
threedots <- threedots$threedots
## --> updated `...` to be passed along to other functions
mthd <- selectMethod(fun, signature = inferSignature(args_this))
## --> `inferSignature()` would need to be able to infer the correct
## signature vector to be passed to `selectMethod()` from `args_this`
## Actual call //
do.call(mthd, c(args_this, threedots))
}
Run Code Online (Sandbox Code Playgroud)
以下是"类型化三点参数容器"的生成器如何显示的说明.
请注意,为了让这种机制跨包时,它将可能是有意义的也提供了可能说明一个特定的功能(arg的命名空间ns和领域.ns):
require("R6")
Threedots <- function(..., fun, ns = NULL) {
name <- if (!is.null(ns)) sprintf("Threedots.%s.%s", ns, fun) else
sprintf("Threedots.%s", fun)
eval(substitute({
INSTANCE <- R6Class(CLASS,
portable = TRUE,
public = list(
.args = "list", ## Argument list
.fun = "character", ## Function name
.ns = "character", ## Namespace of function
initialize = function(..., fun, ns = NULL) {
self$.fun <- fun
self$.ns <- ns
self$.args <- structure(list(), names = character())
value <- list(...)
if (length(value)) {
self$.args <- value
}
}
)
)
INSTANCE$new(..., fun = fun, ns = ns)
},
list(CLASS = name, INSTANCE = as.name(name))
))
}
Run Code Online (Sandbox Code Playgroud)
例
x <- Threedots(y = "hello world!", fun = "foo", ns = "pkg.foo")
x
# <Threedots.pkg.foo.foo>
# Public:
# .args: list
# .fun: foo
# .ns: pkg.foo
# initialize: function
class(x)
# [1] "Threedots.pkg.foo.foo" "R6"
x$.args
# $y
# [1] "hello world!"
Run Code Online (Sandbox Code Playgroud)
实际调用将如下所示:
foobar(x = 10)
foobar(x = 10, Threedots(y = "hello world!", fun = "foo", ns = "pkg.foo"))
foobar(x = 10, Threedots(y = 10, fun = "bar", ns = "pkg.bar"))
foobar(x = 10, Threedots(y = list(a = TRUE), fun = "downTheLine", ns = "pkg.a")))
foobar(x = 10,
Threedots(y = "hello world!", fun = "foo", ns = "pkg.foo"),
Threedots(y = 10, fun = "bar", ns = "pkg.bar),
Threedots(y = list(a = 10), fun = "downTheLine", ns = "pkg.a")
)
Run Code Online (Sandbox Code Playgroud)
查看?setGeneric并搜索"...",然后?dotsMethods.可以定义一个派生的泛型...(仅与其他参数混合,不与调度混合).
.A = setClass("A", contains="numeric")
.B = setClass("B", contains="A")
setGeneric("foo", function(...) standardGeneric("foo"))
setMethod("foo", "A", function(...) "foo,A-method")
setGeneric("bar", function(..., verbose=TRUE) standardGeneric("bar"),
signature="...")
setMethod("bar", "A", function(..., verbose=TRUE) if (verbose) "bar,A-method")
Run Code Online (Sandbox Code Playgroud)
导致
> foo(.A(), .B())
[1] "foo,A-method"
> bar(.A(), .B())
[1] "bar,A-method"
> bar(.A(), .B(), verbose=FALSE)
>
Run Code Online (Sandbox Code Playgroud)
我不知道这是否适合您的其他情况.
| 归档时间: |
|
| 查看次数: |
619 次 |
| 最近记录: |