R 迭代器示例崩溃
R iterator example crashes
这看起来很简单,所以我希望我做错了什么。我升级了 R 和包,但现在我从 运行 包 PDF 中的示例中得到以下内容:
> sessionInfo()
R version 4.1.2 (2021-11-01)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 11.6
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] iterators_1.0.13
loaded via a namespace (and not attached):
[1] compiler_4.1.2 parallel_4.1.2 tools_4.1.2 itertools_0.1-3 rJava_1.0-5
> library(iterators)
> i1 <- iter(1:3)
> nextElem(i1)
Error: StopIteration
>
我没有看到任何其他帖子指出最新版本中的某些内容已损坏,所以我不知道该从哪里开始。感谢您提供任何帮助、链接或信息!
当您 运行 iter(1:3)
时,R 调度到默认方法 iter.default
,其定义为:
function (obj, checkFunc = function(...) TRUE, recycle = FALSE, ...) {
state <- new.env()
state$i <- 0L
state$obj <- obj
n <- length(obj)
it <- list(state = state, length = n, checkFunc = checkFunc, recycle = recycle)
class(it) <- c("containeriter", "iter")
it
}
iter.default
不会执行任何可能导致重复评估结果不同的异常操作(例如,随机数生成)。这意味着 iter(1:3)
应该 始终 评估包含环境 state
绑定 i = 0L
.
的命名列表
在我系统上的 vanilla R (4.1.2) 会话中,它就是这样做的:
$ R --vanilla
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 0
但在 RStudio(桌面版 1.4.1717)中:
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 4
这解释了 nextElem
抛出的 StopIteration
错误;
参见nextElem.containeriter
here的定义(有点长,无法粘贴)。
运行iter(1:3)
在一个调试器下,一行一行,我确定环境state
中i
的值由0L
变为4L
在行 class(it) <- c("containeriter", "iter")
.
> library("iterators")
> debugonce(iterators:::iter.default)
> iter(1:3)
debugging in: iter.default(1:3)
debug: {
state <- new.env()
state$i <- 0L
state$obj <- obj
n <- length(obj)
it <- list(state = state, length = n, checkFunc = checkFunc,
recycle = recycle)
class(it) <- c("containeriter", "iter")
it
}
Browse[2]> n
debug: state <- new.env()
Browse[2]> n
debug: state$i <- 0L
Browse[2]> n
debug: state$obj <- obj
Browse[2]> n
debug: n <- length(obj)
Browse[2]> n
debug: it <- list(state = state, length = n, checkFunc = checkFunc,
recycle = recycle)
Browse[2]> n
debug: class(it) <- c("containeriter", "iter")
Browse[2]> state$i
[1] 0
Browse[2]> n
debug: it
Browse[2]> state$i
[1] 4
Browse[2]>
(这里,n
是给调试器 运行 n ext line 的指令,不是 R 代码。)
有趣的是,当我们访问 iter(1:3)
的结果而不将其分配给名称时,可以避免故障。
> iter(1:3)$state$i
[1] 0
当我们完全移除 iterators
界面时,也 避免了故障。
> f <- function (obj, checkFunc = function(...) TRUE, recycle = FALSE, ...) {
+ state <- new.env()
+ state$i <- 0L
+ state$obj <- obj
+ n <- length(obj)
+ it <- list(state = state, length = n, checkFunc = checkFunc, recycle = recycle)
+ class(it) <- c("containeriter", "iter")
+ it
+ }
> x <- f(1:3)
> x$state$i
[1] 0
所以,似乎是内存损坏,原因似乎是iterators
之间的相互作用和 RStudio。可能值得将问题报告给 RStudio here [edit: I've just done this; see here] and keeping the iterators
maintainers in the loop here [edit: I've also done this; see here)。
FWIW,这是我的系统详细信息。尚不清楚问题是否与平台有关...
R version 4.1.2 (2021-11-01)
Platform: aarch64-apple-darwin20.6.0 (64-bit)
Running under: macOS Big Sur 11.6.1
更新
一位 RStudio 工程师回复了我的 issue。以下是他们回应的详细说明:
默认情况下,RStudio 在绑定到全局环境中的对象上静默调用 str
,以便使用有用的信息填充环境窗格。因此,一旦您在全局环境中分配 x <- iter(1:3)
:
- RStudio 静默评估
str(x)
。
- R 调度到
str.default
。
str.default
计算 vapply(x, typeof, "")
.
vapply
计算 as.list(x)
.
- R 调度到
as.list.iter
(源代码 here)。
as.list.iter
遍历 1:3
. 的所有元素
因此,x$state$i
的值以 1:3
的长度加一结束。
我们可以像这样在 vanilla R 中重现 RStudio 的行为:
$ R --vanilla
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 0
> as.list(x)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
> x$state$i
[1] 4
要避开 RStudio 的自动 str
,您可以将环境窗格设置为“仅手动刷新”。更永久的修复将要求 iterators
维护者为 class "iter"
编写 str
方法或重构他们的 as.list
方法。
这看起来很简单,所以我希望我做错了什么。我升级了 R 和包,但现在我从 运行 包 PDF 中的示例中得到以下内容:
> sessionInfo()
R version 4.1.2 (2021-11-01)
Platform: x86_64-apple-darwin17.0 (64-bit)
Running under: macOS Big Sur 11.6
Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.1/Resources/lib/libRlapack.dylib
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] iterators_1.0.13
loaded via a namespace (and not attached):
[1] compiler_4.1.2 parallel_4.1.2 tools_4.1.2 itertools_0.1-3 rJava_1.0-5
> library(iterators)
> i1 <- iter(1:3)
> nextElem(i1)
Error: StopIteration
>
我没有看到任何其他帖子指出最新版本中的某些内容已损坏,所以我不知道该从哪里开始。感谢您提供任何帮助、链接或信息!
当您 运行 iter(1:3)
时,R 调度到默认方法 iter.default
,其定义为:
function (obj, checkFunc = function(...) TRUE, recycle = FALSE, ...) {
state <- new.env()
state$i <- 0L
state$obj <- obj
n <- length(obj)
it <- list(state = state, length = n, checkFunc = checkFunc, recycle = recycle)
class(it) <- c("containeriter", "iter")
it
}
iter.default
不会执行任何可能导致重复评估结果不同的异常操作(例如,随机数生成)。这意味着 iter(1:3)
应该 始终 评估包含环境 state
绑定 i = 0L
.
在我系统上的 vanilla R (4.1.2) 会话中,它就是这样做的:
$ R --vanilla
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 0
但在 RStudio(桌面版 1.4.1717)中:
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 4
这解释了 nextElem
抛出的 StopIteration
错误;
参见nextElem.containeriter
here的定义(有点长,无法粘贴)。
运行iter(1:3)
在一个调试器下,一行一行,我确定环境state
中i
的值由0L
变为4L
在行 class(it) <- c("containeriter", "iter")
.
> library("iterators")
> debugonce(iterators:::iter.default)
> iter(1:3)
debugging in: iter.default(1:3)
debug: {
state <- new.env()
state$i <- 0L
state$obj <- obj
n <- length(obj)
it <- list(state = state, length = n, checkFunc = checkFunc,
recycle = recycle)
class(it) <- c("containeriter", "iter")
it
}
Browse[2]> n
debug: state <- new.env()
Browse[2]> n
debug: state$i <- 0L
Browse[2]> n
debug: state$obj <- obj
Browse[2]> n
debug: n <- length(obj)
Browse[2]> n
debug: it <- list(state = state, length = n, checkFunc = checkFunc,
recycle = recycle)
Browse[2]> n
debug: class(it) <- c("containeriter", "iter")
Browse[2]> state$i
[1] 0
Browse[2]> n
debug: it
Browse[2]> state$i
[1] 4
Browse[2]>
(这里,n
是给调试器 运行 n ext line 的指令,不是 R 代码。)
有趣的是,当我们访问 iter(1:3)
的结果而不将其分配给名称时,可以避免故障。
> iter(1:3)$state$i
[1] 0
当我们完全移除 iterators
界面时,也 避免了故障。
> f <- function (obj, checkFunc = function(...) TRUE, recycle = FALSE, ...) {
+ state <- new.env()
+ state$i <- 0L
+ state$obj <- obj
+ n <- length(obj)
+ it <- list(state = state, length = n, checkFunc = checkFunc, recycle = recycle)
+ class(it) <- c("containeriter", "iter")
+ it
+ }
> x <- f(1:3)
> x$state$i
[1] 0
所以,似乎是内存损坏,原因似乎是iterators
之间的相互作用和 RStudio。可能值得将问题报告给 RStudio here [edit: I've just done this; see here] and keeping the iterators
maintainers in the loop here [edit: I've also done this; see here)。
FWIW,这是我的系统详细信息。尚不清楚问题是否与平台有关...
R version 4.1.2 (2021-11-01)
Platform: aarch64-apple-darwin20.6.0 (64-bit)
Running under: macOS Big Sur 11.6.1
更新
一位 RStudio 工程师回复了我的 issue。以下是他们回应的详细说明:
默认情况下,RStudio 在绑定到全局环境中的对象上静默调用 str
,以便使用有用的信息填充环境窗格。因此,一旦您在全局环境中分配 x <- iter(1:3)
:
- RStudio 静默评估
str(x)
。 - R 调度到
str.default
。 str.default
计算vapply(x, typeof, "")
.vapply
计算as.list(x)
.- R 调度到
as.list.iter
(源代码 here)。 as.list.iter
遍历1:3
. 的所有元素
因此,x$state$i
的值以 1:3
的长度加一结束。
我们可以像这样在 vanilla R 中重现 RStudio 的行为:
$ R --vanilla
> library("iterators")
> x <- iter(1:3)
> x$state$i
[1] 0
> as.list(x)
[[1]]
[1] 1
[[2]]
[1] 2
[[3]]
[1] 3
> x$state$i
[1] 4
要避开 RStudio 的自动 str
,您可以将环境窗格设置为“仅手动刷新”。更永久的修复将要求 iterators
维护者为 class "iter"
编写 str
方法或重构他们的 as.list
方法。