为什么空逻辑向量能通过 stopifnot() 检查?
Why does empty logical vector pass the stopifnot() check?
今天我发现我的一些 stopifnot()
测试失败了,因为传递的参数计算为空逻辑向量。
这是一个例子:
stopifnot(iris$nosuchcolumn == 2) # passes without error
这是非常不直观的,似乎与其他一些行为相矛盾。考虑:
isTRUE(logical())
> FALSE
stopifnot(logical())
# passes
所以即使这个参数不是 TRUE
,stopifnot()
也会通过。
但是此外,上面的行为对于不同类型的空向量是不同的。
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.
今天我发现我的一些 stopifnot()
测试失败了,因为传递的参数计算为空逻辑向量。
这是一个例子:
stopifnot(iris$nosuchcolumn == 2) # passes without error
这是非常不直观的,似乎与其他一些行为相矛盾。考虑:
isTRUE(logical())
> FALSE
stopifnot(logical())
# passes
所以即使这个参数不是 TRUE
,stopifnot()
也会通过。
但是此外,上面的行为对于不同类型的空向量是不同的。
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 dimensionsc(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.