本文介绍了通过`说法调度...`(三个点)在不同的调用栈层的多种功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

海事组织,它不是的<一个公正的精确副本href=\"http://stackoverflow.com/questions/25376197/split-up-arguments-and-distribute-to-multiple-functions?lq=1\">question这被称为的:

我的问题中涉及的 N -step调度 N = 2 在参数实际例子) ... 巴()富()不可以都直接调用在 foobar的(),但 foobar的()只要求富()这反过来又调用作为答案提供了巴()和解决方案的不考虑到这一点。我希望社会认识到这一问题,并打开了这个问题了。

不过,我已经提供了声明我目前的解决方案,它考虑到答案的问题提到给出很好的建议答案。然而,我会很感激听到更好的解决方案或不同的方法。


我不知道是否有一个聪明的方式来微调控制参数是通过R的三个点的说法调度的确切方式 ...

考虑以下用例:


  • 您有一个函数 foobar的()调用富()这反过来又来电巴()

  • 两个富()巴()有一个被称为一个参数,但他们每个人都有一个不同的意义

  • 在调用 foobar的(),你想说这里的富()和这里的巴()这就是我想完成的东西。

如果你简单地调用 foobar的(X =李四,Y =Hello World的)只得到的分派到富()在调用巴()的东西必须是为了明确要调度(即调用必须是巴(X = X,Y = Y)而不是巴(X = X,.. 。)。此外,这将是错误的巴()的角度反正:

 富&LT;  - 功能(X,Y =一些字符,...){
  消息(富----------)
  消息(富/ threedots)
  尝试(打印(列表(...)))
  消息(富/ Y)
  尝试(打印(Y))
  巴(X = X,...)
}
巴≤; - 功能(X,Y = TRUE,...){
  消息(巴----------)
  消息(酒吧/ threedots)
  尝试(打印(列表(...)))
  消息(巴/ Y)
  尝试(打印(Y))
  回报(paste0(你好,X))
}
foob​​ar的&LT; - 功能(X,...){
  消息(FOOBAR ----------)
  消息(FOOBAR / threedots)
  尝试(打印(列表(...)))
  美孚(X = X,...)
}foob​​ar的(X =李四,Y =你好)
#foobar的----------
#foobar的/ threedots
#$ Y
#[1]你好

#富----------
#富/ threedots
#列表()
#富/ Y
#[1]你好
#杆----------
#酒吧/ threedots
#列表()
#酒吧/年
#[1] TRUE
#[1]你好:李四

我概念性想什么,能够做的就是这样的:

  foobar的(X =李四,y_foo =世界,你好!,y_bar = FALSE)

下面是工作但做法也感到非​​常奇怪:

 富&LT;  - 功能(X,Y =一些字符,...){
  消息(富----------)
  消息(富/ threedots)
  尝试(打印(列表(...)))
  消息(富/ Y)
  精氨酸&下; - paste0(Y_,sys.call()[[1]])
  如果(精氨酸%中%名称(列表(...))){
    Y'LT; - 列表(...)[[参数]
  }
  尝试(打印(Y))
  巴(X = X,...)
}
巴≤; - 功能(X,Y = TRUE,...){
  消息(巴----------)
  消息(酒吧/ threedots)
  尝试(打印(列表(...)))
  消息(巴/ Y)
  精氨酸&下; - paste0(Y_,sys.call()[[1]])
  如果(精氨酸%中%名称(列表(...))){
    Y'LT; - 列表(...)[[参数]
  }
  尝试(打印(Y))
  回报(paste0(你好,X))
}foob​​ar的(X =李四,y_foo =世界,你好!,y_bar = FALSE)
#foobar的----------
#foobar的/ threedots
#$ y_foo
#[1]世界,你好!

#$ y_bar
#[1] FALSE

#富----------
#富/ threedots
#$ y_foo
#[1]世界,你好!

#$ y_bar
#[1] FALSE

#富/ Y
#[1]世界,你好!
#杆----------
#酒吧/ threedots
#$ y_foo
#[1]世界,你好!

#$ y_bar
#[1] FALSE

#酒吧/年
#[1] FALSE
#[1]你好:李四

您会如何去实现这样的事情?

我也S4方法分发发挥四周,看看我是否能定义一个特征参数 ... 方法,但没有去太清楚(和它的可能是一个非常不好的想法):

  setGeneric(
  NAME =foo的,
  签名= C(X,...),
  高清=功能(X,...)standardGeneric(富)

使用setMethod(
  F =富,
  签名=签名(X =性格,...=MyThreeDotsForAFunctionImCalling),
 定义=功能(X,...)巴(X = X)

## - &GT;不工作


解决方案

当前的解决方案

请注意,如果可能,我不想 foobar的()富()巴()包含的之后的调用的函数(如 y_foo 或 args_bar )。他们应该能够采取随后调用的函数可以处理,并相应地通过他们的投入。当然,这将需要明确和良好的各自的功能说明。

定义

  withThreedots&LT;  - 函数(FUN,...){
  threedots&LT; - 列表(...)
  IDX&LT; - 这(单位:%sprintf的名称(threedots)%(args_%的,有趣))
  的eval(替代(
    do.call(FUN,C(THREE_THIS,THREE_REST))
    列表(
      FUN = as.name(有趣),
      THREE_THIS =如果(长度(IDX))threedots [[idx的],
      THREE_REST = IF(长度(IDX))threedots [-idx]其他threedots
    )
  ))
}#@title
#'的东西是否FOOBAR

#'@description
#'调用\\ code {\\链接[foo.package] {富}}。

通过#'@section参数调度...:

#'调用后续函数是由函数处理
#'\\ code {\\ {链接} withThreedots}。为了使它调度正确
#'参数的各种功能进一步下跌的调用栈,
#'你需要用他们在一个单独的列表,并根据他们的名字
#'以下约定:\\ code {args_&lt;作用-名称&gt;}。

#例如,参数应传递到
#'\\ code {\\链接[foo.package] {} foo的需要加以说明如下:
#'\\ code {args_foo =名单(Y =世界,你好!)}。这同样适用于参数
#'是\\ code {\\链接[foo.package] {} foo的传递给它的后续功能。

#'@param点¯x\\ code {\\ {链接字符}}。一些参数。
#'@参数...更多参数传递给后续函数。
#' 尤其是:
#'\\ {逐项
#'\\项目{\\ code {\\链接[foo.package] {富}}。确保也检查
#'这个功能又可以通过\\ code {...}沿参数传递。
#在这种情况下,你也可以包括那些论据。}
#'}
#'见\\强有关细节{参数通过调度...}
#'预期的事物对象结构通过\\ code {...}通过。
#'@example研究所/例子/ existsNested.r
#'@seealso \\ code {\\链接[foo.package] {富}}
#' @出口
foob​​ar的&LT; - 功能(X,...){
  withThreedots(富,X = X,...)
}富&LT; - 功能(X = X,Y =一些文本,...){
  消息(富/ Y)
  打印(Y)
  withThreedots(酒吧,X = X,...)
}
巴≤; - 函数(X = X,Y = 1,...){
  消息(巴/ Y)
  打印(Y)
  withThreedots(downTheLine,X = X,...)
}
downTheLine&LT; - 功能(X = X,Y =列表(),...){
  消息(downTheLine / Y)
  打印(Y)
}

应用

  foobar的(X = 10)
foob​​ar的(X = 10,args_foo =名单(Y =世界,你好!))
foob​​ar的(X = 10,args_bar =名单(Y = 10))
foob​​ar的(X = 10,args_downTheLine =名单(Y =列表(= TRUE)))foob​​ar的(X = 10,
       args_foo =名单(Y =世界,你好!)
       args_bar =名单(Y = 10),
       args_downTheLine =名单(Y =列表(= TRUE))
)#富/ Y
#[1]世界,你好!
#酒吧/年
#[1] 10
#downTheLine / Y
#$一个
#[1] TRUE

使用内置在S4中调度

怎样才是真正整洁是,如果人们可以定义 ... S4方法,并有内置的调度员做的工作是 withThreedots ()目前一样。而不是列表 args_&lt;作用&GT; 人会使用的类实例沿 Threedots $新的(小于线; ARGS-列表&gt;,&lt;作用-name&GT;)。有谁知道,如果这样的事情可以做?

IMO, it's not just an exact duplicate of the question that is being referred to:

My question involves a n-step dispatch (n = 2 in the actual example) of arguments in ...: bar() and foo() are not both called directly inside foobar(), but foobar() only calls foo() which in turn calls bar() and solutions as provided in the answers do not account for this. I hope the community recognizes this aspects and opens this question up.

However, I've included an answer that states my current solution which takes into account the great suggestions given in the answer to the referred question. Yet, I'd be grateful to hear about better solutions or different approaches.


I wonder if there's a clever way to fine control the exact way arguments are dispatched via R's "three dots" argument ....

Consider the following use case:

  • you have a function foobar() that calls foo() which in turn calls bar()
  • both foo() and bar() have an argument that's called y, but they each have a different meaning
  • in the call to foobar(), you would like to say "here's the y for foo() and here's the y for bar()". That's what I would like to accomplish.

If you simply call foobar(x = "John Doe", y = "hello world"), y only get's dispatched to foo() as in the call to bar() things would have to be explicit in order to be dispatched (i.e. the call would have to be bar(x = x, y = y) instead of bar(x = x, ...). Plus, it would be the "wrong" y from bar()'s perspective anyway:

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"

What I conceptionally would like to be able to do is something like this:

foobar(x = "John Doe", y_foo = "hello world!", y_bar = FALSE)

Here's an approach that works but that also feels very odd:

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"

How would you go about implementing something like this?

I also played around with S4 method dispatch to see if I could define methods for a signature argument ..., but that didn't go too well (and it's probably a very bad idea anyway):

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
解决方案

Current solution

Note that if possible I wouldn't want foobar(), foo() or bar() to contain any explicit arguments of subsequently called functions (e.g. y_foo or args_bar). They should just be able to take any inputs that subsequently called functions can process and pass them along accordingly. Of course this would need to be clearly and well documented for the respective functions.

Definitions

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)
}

Apply

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

Using the built-in S4 dispatcher

What would really be neat is if one could define S4 methods for ... and have the built-in dispatcher do the job that withThreedots() currently does. Instead of a list args_<function> one would use class instances along the line of Threedots$new(<args-list>, <function-name>). Does anyone know if something like this could be done?

这篇关于通过`说法调度...`(三个点)在不同的调用栈层的多种功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-27 16:34