簡體   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