为什么空逻辑向量能通过 stopifnot() 检查?

Why does empty logical vector pass the stopifnot() check?

今天我发现我的一些 stopifnot() 测试失败了,因为传递的参数计算为空逻辑向量。

这是一个例子:

stopifnot(iris$nosuchcolumn == 2)  # passes without error

这是非常不直观的,似乎与其他一些行为相矛盾。考虑:

isTRUE(logical())
> FALSE

stopifnot(logical())
# passes

所以即使这个参数不是 TRUEstopifnot() 也会通过。
但是此外,上面的行为对于不同类型的空向量是不同的。

isTRUE(numeric())
> FALSE

stopifnot(numeric())
# Error: numeric() are not all TRUE

以上是否有逻辑,或者这应该被视为错误?

akrun 和 r2evans 的评论很到位。

但是,要详细说明为什么会发生这种情况以及为什么您对 isTRUE() 行为感到困惑,请注意 stopifnot() 检查三件事;检查是(其中 r 是您传递的表达式的结果):

if (!(is.logical(r) && !anyNA(r) && all(r)))

所以,让我们来看看:

is.logical(logical())
# [1] TRUE
!anyNA(logical())
# [1] TRUE
all(logical())
# [1] TRUE

is.logical(numeric())
# [1] FALSE
!anyNA(numeric())
# [1] TRUE
all(numeric())
# [1] TRUE

因此,logical() 通过而 numeric() 失败的唯一原因是因为 numeric() 不是 akrun 所建议的 "logical,"。出于这个原因,您应该避免可能导致长度为 0 的逻辑向量的检查,如 r2evans 所建议的那样。

其他答案涵盖了 stopifnot 行为的实际原因;但我同意 Karolis 的观点,the thread linked by Henrik 添加了对为什么会这样的真实解释:

As author stopifnot(), I do agree with [OP]'s "gut feeling" [...] that stopifnot(dim(x) == c(3,4)) [...][should] stop in the case where x is a simple vector instead of a matrix/data.frame/... with dimensions c(3,4) ... but [...] the gut feeling is wrong because of the fundamental lemma of logic: [...]

"All statements about elements of the empty set are true"

Martin Maechler, ETH Zurich

Also, [...], any() is to "|" what sum() is to "+" and what all() is to "&" and prod() is to "*". All the operators have an identity element, namely FALSE, 0, TRUE, and 1 respectively, and the generic convention is that for an empty vector, we return the identity element, for the reason given above.

Peter D.