我很惊讶missing
似乎没有在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
显式作品如excepted:
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
既没有缺少也没有可访问。这里发生了什么?
(我知道我可以通过设置arg=NULL
中的wrapper
和if (is.null(arg))
中的.add
或其他内容来规避这一点。.add
是一个内部函数根据输入(例如arg
)自行确定arg=mean(x)
,我希望arg
中的wrapper
为用户记录参数arg
,并为允许用户覆盖默认行为。最重要的是:我想了解为什么这不起作用!)
EDIT2 :最后这个行为是固定的。这是R中的一个错误。 3.2.0,见PR#15707。
答案 0 :(得分:5)
首先,我提到我认为这样做的惯用方法是构建一个调用然后对其进行评估。有关示例,请参阅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的回答一样。
首先,我将解决&#34;默认值&#34;问题,因为我认为它更直截了当。我认为这个可以更简单,如下面的两个函数,其中第二个(f2
)只调用第一个(f1
)。我们看到f1
中的默认参数被x
中f2
的承诺所覆盖,并且当评估该承诺时,它将丢失。这个故事的道德(我认为);如果调用中包含该变量,则必须在调用函数中再次设置默认值。
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
放在..1
中,所以它看起来并不缺失,但当它试图评估时,它发现它丢失了。这个故事的道德(我认为);不要尝试通过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
答案 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