IMO,它不仅仅是question that is being referred to的完全重复:
我的问题涉及n
中n = 2
:...
和{{{{}} bar()
中的参数的 foo()
- 步骤调度(foobar()
) 1}} 不都在foobar()
内直接调用,但foo()
只调用bar()
,后者又调用...
和解决方案答案没有考虑到这一点。我希望社区能够认识到这些方面并提出这个问题。
但是,我已经提供了一个答案,说明了我目前的解决方案,该解决方案考虑了所提问题答案中给出的重要建议。然而,我很高兴听到更好的解决方案或不同的方法。
我想知道是否有一种聪明的方法来精确控制参数通过R"三个点"参数foobar()
。
考虑以下用例:
foo()
,可以拨打bar()
来调用foo()
bar()
和y
都有一个名为foobar()
的论据,但每个都有不同含义 y
时,您想说的是foo()
y
bar()
和foobar(x = "John Doe", y = "hello world")
y
} foo()
"。 这就是我想要完成的事情。如果您只是致电bar()
,bar(x = x, y = y)
只会被调度到bar(x = x, ...)
,因为在y
的调用中,事情必须是明确的,以便被派遣(即,呼叫必须是bar()
而不是foo <- function(x, y = "some character", ...) {
message("foo ----------")
message("foo/threedots")
try(print(list(...)))
message("foo/y")
try(print(y))
bar(x = x, ...)
}
bar <- function(x, y = TRUE, ...) {
message("bar ----------")
message("bar/threedots")
try(print(list(...)))
message("bar/y")
try(print(y))
return(paste0("hello: ", x))
}
foobar <- function(x, ...) {
message("foobar ----------")
message("foobar/threedots")
try(print(list(...)))
foo(x = x, ...)
}
foobar(x = "John Doe", y = "hi there")
# foobar ----------
# foobar/threedots
# $y
# [1] "hi there"
#
# foo ----------
# foo/threedots
# list()
# foo/y
# [1] "hi there"
# bar ----------
# bar/threedots
# list()
# bar/y
# [1] TRUE
# [1] "hello: John Doe"
。此外,它将是来自foobar(x = "John Doe", y_foo = "hello world!", y_bar = FALSE)
&#的错误&#34; foo <- function(x, y = "some character", ...) {
message("foo ----------")
message("foo/threedots")
try(print(list(...)))
message("foo/y")
arg <- paste0("y_", sys.call()[[1]])
if (arg %in% names(list(...))) {
y <- list(...)[[arg]]
}
try(print(y))
bar(x = x, ...)
}
bar <- function(x, y = TRUE, ...) {
message("bar ----------")
message("bar/threedots")
try(print(list(...)))
message("bar/y")
arg <- paste0("y_", sys.call()[[1]])
if (arg %in% names(list(...))) {
y <- list(...)[[arg]]
}
try(print(y))
return(paste0("hello: ", x))
}
foobar(x = "John Doe", y_foo = "hello world!", y_bar = FALSE)
# foobar ----------
# foobar/threedots
# $y_foo
# [1] "hello world!"
#
# $y_bar
# [1] FALSE
#
# foo ----------
# foo/threedots
# $y_foo
# [1] "hello world!"
#
# $y_bar
# [1] FALSE
#
# foo/y
# [1] "hello world!"
# bar ----------
# bar/threedots
# $y_foo
# [1] "hello world!"
#
# $y_bar
# [1] FALSE
#
# bar/y
# [1] FALSE
# [1] "hello: John Doe"
无论如何,我的观点是:
...
我在概念上希望能做的是这样的事情:
setGeneric(
name = "foo",
signature = c("x", "..."),
def = function(x, ...) standardGeneric("foo")
)
setMethod(
f = "foo",
signature = signature(x = "character", "..." = "MyThreeDotsForAFunctionImCalling"),
definition = function(x, ...) bar(x = x)
)
## --> does not work
这是一种有效的方法,但也感觉很奇怪:
{{1}}
你会如何实现这样的目标?
我还使用S4方法调度来查看我是否可以为签名参数{{1}}定义方法,但这并不是很好(这可能是一个非常糟糕的主意反正):
{{1}}
答案 0 :(得分:0)
请注意,如果可能,我不希望foobar()
,foo()
或bar()
包含后续调用函数的任何显式参数(例如{ {1}}或y_foo
)。他们应该能够接受随后被称为函数的任何输入,并相应地传递它们。当然,这需要为各自的功能清楚地记录下来。
args_bar
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
)
))
}
#' @title
#' Does something foobar
#'
#' @description
#' Calls \code{\link[foo.package]{foo}}.
#'
#' @section Argument dispatch via ...:
#'
#' Calling subsequent functions is handled by function
#' \code{\link{withThreedots}}. In order for it to dispatch the correct
#' arguments to the various functions further down the calling stack,
#' you need to wrap them in a individual lists and name them according to
#' the following convention: \code{args_<function-name>}.
#'
#' For example, arguments that should be passed to
#' \code{\link[foo.package]{foo} would need to be stated as follows:
#' \code{args_foo = list(y = "hello world!")}. The same goes for arguments
#' that \code{\link[foo.package]{foo} passes to its subsequent functions.
#'
#' @param x \code{\link{character}}. Some argument.
#' @param ... Further arguments to be passed to subsequent functions.
#' In particular:
#' \itemize{
#' \item{\code{\link[foo.package]{foo}}. Make sure to also check if
#' this function in turn can pass along arguments via \code{...}.
#' In this case, you can also include those arguments.}
#' }
#' See section \strong{Argument dispatch via ...} for details about the
#' expected object structure of things to pass via \code{...}.
#' @example inst/examples/existsNested.r
#' @seealso \code{\link[foo.package]{foo}}
#' @export
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)
}
如果可以为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
定义S4方法并让内置调度程序执行...
当前所做的工作,那么真正优秀的是什么。可以使用withThreedots()
行中的类实例而不是列表args_<function>
。有谁知道这样的事情可以做到吗?