繁体   English   中英

为什么`missing`和默认参数在`lapply`调用的函数中不起作用?

[英]Why `missing` and default arguments are not working in functions called by `lapply`?

我很惊讶missing似乎不适用于lapply调用的lapply 假设我有以下功能:

.add <- function(x, arg, ...) {
  if (missing(arg)) {
    arg <- 1
  }
  print(match.call())
  return(x + arg)
}

wrapper <- function(l, arg, ...) {
  return(lapply(l, .add, arg=arg, ...))
}

arg显式设置为例外:

wrapper(list(x=1:10, y=1:10), arg=1)
#FUN(x = X[[1L]], arg = ..1)
#FUN(x = X[[2L]], arg = ..1)
#$x
# [1]  2  3  4  5  6  7  8  9 10 11
#
#$y
# [1]  2  3  4  5  6  7  8  9 10 11

没有arg我会期望相同的输出,但它失败了:

wrapper(list(x=1:10, y=1:10))
#FUN(x = X[[1L]], arg = ..1)
# Error in FUN(X[[1L]], ...) : argument "arg" is missing, with no default

missing在嵌套包装函数中工作,其中没有使用lapply 为什么它似乎对lapply调用的函数没有影响?

编辑 :默认参数也不起作用:

.add <- function(x, arg=5, ...) {
  if (missing(arg)) {
    arg <- 1
  }
  print(match.call())
  return(x + arg)
}

wrapper(list(x=1:10, y=1:10))
#FUN(x = X[[1L]], arg = ..1)
# Error in FUN(X[[1L]], ...) : argument "arg" is missing, with no default

似乎arg既不缺少也不可访问 这里发生了什么?

(我知道我可以通过在wrapper设置arg=NULL并在.add或其他地方设置if (is.null(arg))来绕过这个.add是一个内部函数,它根据输入确定arg (例如arg=mean(x)我想argwrapper记录参数arg的用户,并允许用户覆盖默认行为,最重要的:!我想知道这是为什么不工作)

EDIT2 :最后这个行为是固定的。 这是一个R <3.2.0的错误,见PR#15707

首先,我要提到的是,我认为这样做的惯用方法是构建一个调用然后对其进行评估。 有关write.csv ,请参见write.csv 我相信这段代码会使用该方法做你想做的事。

wrapper <- function(X, arg, ...) {
  force(X) # optional; if X is missing, the error message will be more informative
  Call <- match.call(expand.dots=TRUE)
  Call[[1L]] <- as.name("lapply")
  Call$FUN <- as.name(".add")
  eval.parent(Call)
}

好的,现在这是试图解释你发现的问题。 我也随时准备好纠正,但希望这至少有助于澄清问题,就像@ idfah的回答一样。

首先,我将解决“默认”问题,因为我认为它更直接。 我认为这个可以更简单,如下面的两个函数,其中第二个( f2 )只调用第一个( f1 )。 我们看到的是f1中的默认参数被f2 x的promise所覆盖,并且当评估该promise时,它将丢失。 这个故事的道德(我认为); 如果调用中包含该变量,则必须在调用函数中再次设置默认值。

f1 <- function(x=1) {print(match.call()); x}
f2 <- function(x) {f1(x=x)}
f1()
## f1()
## [1] 1
f2()
## f1(x = x)
## Error in f1(x = x) : argument "x" is missing, with no default

现在lapply问题中的缺失。 在这里我基本上有sgibb的代码,但是添加了一个关于arg是否被认为缺失的消息。 我们有一个好奇的矛盾; 该消息告诉我们arg不会丢失,但是当函数尝试访问它时,我们会收到一条错误消息,告诉我们缺少arg

.add <- function(x, arg) {
  print(match.call())
  if(missing(arg)) {
    message("arg is missing in .add")
    x
  } else {
    message("arg is not missing")
    x + arg
  }
}
wrapper <- function(l, arg) {lapply(l, .add, arg=arg)}
wrapper(1)
## FUN(x = 1[[1L]], arg = ..1)
## arg is not missing
## Error in FUN(1[[1L]], ...) : argument "arg" is missing, with no default

我认为正在发生的是lapply承诺arg in ..1 ,所以它看起来并不缺少,但当它试图评估它时,它发现它缺失了。 这个故事的道德(我认为); 不要尝试通过lapply传播lapply

更新:更准确地说,它是点扩展如何工作的东西。 考虑这个版本的lapply (它实际上不在列表上工作,但在其他方面具有相同的代码样式); 这表明我们得到了相同的行为。

apply3 <- function(X, FUN, ...) { 
  print(match.call())
  FUN(X, ...)
}
wrapper3 <- function(l, arg) {apply3(l, .add, arg=arg)}
wrapper3(1)
## apply3(X = l, FUN = .add, arg = arg)
## FUN(x = X, arg = ..1)
## arg is not missing
## Error in FUN(X, ...) : argument "arg" is missing, with no default

但是当我们用变量名替换点时,它按预期工作。

apply4 <- function(X, FUN, hm) { 
  print(match.call())
  FUN(X, hm)
}
wrapper4 <- function(l, arg) {apply4(l, .add, hm=arg)}
wrapper4(1)
## apply4(X = l, FUN = .add, hm = arg)
## FUN(x = X, arg = hm)
## arg is missing in .add
## [1] 1

还有一个例子; 如果我使用点,但自己做扩展,直接调用..1 ,它也有效! 这很奇怪,因为匹配的调用与不起作用的版本相同。

apply3b <- function(X, FUN, ...) { 
  print(match.call())
  FUN(X, ..1)
}
wrapper3b <- function(l, arg) {apply3b(l, .add, arg=arg)}
wrapper3b(1)
## apply3b(X = l, FUN = .add, arg = arg)
## FUN(x = X, arg = ..1)
## arg is missing in .add
## [1] 1

你的包装中没有missing ,所以它在那里炸弹。 在这种情况下,您不需要它,因为您无论如何都在使用可变参数。 试试这个:

.add <- function(x, arg, ...) {
    if (missing(arg)) 
      arg <- 1
    print(match.call())
  return(x + arg)
}

wrapper <- function(l, ...) 
  return(lapply(l, .add, ...))

如果包装器需要知道arg ,那么你需要在那里missing

.add <- function(x, arg, ...) {
  print(match.call())
  return(x + arg)
}

wrapper <- function(l, ...) {
  if (missing(arg)) 
    arg <- 1
  return(lapply(l, .add, arg=arg, ...))
}

我纠正了

以下示例允许missing位于调用堆栈的底部,可能是因为惰性求值。 我不确定为什么你的例子不起作用......好奇。

wrapper.c <- function(l, arg)
{
  if (missing(arg))
    arg <- 1
  print("I'm in c")
  arg
}

wrapper.b <- function(l, arg)
{
  print("I'm in b")
  wrapper.c(l, arg)
}

wrapper.a <- function(l, arg)
  wrapper.b(l, arg)

> wrapper.a(1)
[1] "I'm in b"
[1] "I'm in c"
[1] 1

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM