R:函数工厂的管道输入

R: Piping input to a function factory

在 R 中,我有一个输出函数的函数(称为函数工厂)。 但是,当使用 %>% 向其输入管道时,会产生奇怪的错误。

这是一个简化的例子:

ax <- function(a) {
  function(x) a*x
}

library(magrittr)
3 %>% ax() %>% plot # Error in a * x : non-numeric argument to binary operator
ax(3) %>% plot      # works, a plot of y=3x is produced

Hadley's book 引导我尝试将 force(a) 插入到 ax 的函数体中。 现在,在这两种情况下都会产生一个情节。

但我不明白为什么会这样。对我来说,这两个案例本质上是相同的。为什么第一种情况需要 force() 而第二种情况不需要?

这是因为这个错误:https://github.com/tidyverse/magrittr/issues/195

更新:安装magrittr的开发版本。显然这个问题已经解决了,但没有人意识到这一点。 remotes::install_github("tidyverse/magrittr")

两年了没人碰管道代码

他们的根本问题是 R Lazy evaluation。当您将参数传递给函数时,直到需要它时才会对其求值。

有关此示例,请尝试以下代码:

funs <- list()
for (i in 1:3) {
  funs[[i]] <- ax(i)
}
# i is not evaluated until now. it has been modified before it is evaluated so all the calls evaluate a to the current value of i (i=3)
print(funs[[3]](1))
print(funs[[2]](1))
print(funs[[1]](1))
# lapply creates an environment for each iteration. Even though the evaluation is delayed, it maps to the expected value of a
funs2 <- lapply(1:3, ax)
print(funs2[[3]](1))
print(funs2[[2]](1))
print(funs2[[1]](1))

如果添加 force(a),则在调用 ax 时强制计算 a,而不是在调用 funs[[i]] 时强制计算 a,从而获得预期的行为。

如果我准确地追踪到错误发生的原因,我可能已经向 magrittr 提交了拉取请求。也许值得花一些时间调试它......或者也许有人会很快实现一个基于 rlang 的管道,它具有更小且更易于遵循的实现,可以修复 magrittr 的大部分缺点。 (有关更多详细信息,请参阅 magrittr 存储库中的问题)