强制 R 函数调用自给自足

Force R function call to be self-sufficient

我正在寻找一种方法来调用不受 .GlobalEnv 中其他对象影响的函数。

看看下面的两个函数:

y = 3
f1 = function(x) x+y

f2 = function(x) {
   library(dplyr)
   x %>%
       mutate(area = Sepal.Length *Sepal.Width) %>%
       head()
}

在这种情况下:

现在,我可以将 f1f2 的环境覆盖为 baseenv()new.env(parent=environment(2L)):

environment(f1) = baseenv()
environment(f2) = baseenv()
f1(3)    # fails, as it should
f2(iris) # fails, because %>% is not in function env

或:

# detaching here makes `dplyr` inaccessible for `f2`
# not detaching leaves `head` inaccessible for `f2`
detach("package:dplyr", unload=TRUE)
environment(f1) = new.env(parent=as.environment(2L))
environment(f2) = new.env(parent=as.environment(2L))
f1(3)    # fails, as it should
f2(iris) # fails, because %>% is not in function env

有没有办法覆盖函数的环境,使其必须自给自足,但只要它加载自己的库,它也总是有效?

这里的问题是,从根本上说,library 和类似的工具不提供作用域,也不是为了与作用域一起工作而设计的:1尽管 library 是在函数内部执行的,但它的作用实际上是全局的,而不是局部的。

具体来说,您将函数与全局环境隔离的方法是合理的;然而,library 操纵 search 路径(通过 attach),并且函数的环境不会“通知”这一点:它仍然指向 previous 第二个搜索路径条目作为其总parent.

library/attach/... 被调用时,您需要找到一种方法 更新 函数环境的 grandparent 环境。您可以通过将函数的 parent 环境中的 library 等替换为您自己调用 attach 的修改版本的版本来实现此目的。这个 attach2 不仅会调用原来的 attach,还会重新链接您环境的 parent。


1 顺便说一句,“box”解决了所有这些问题。在您的代码中将 library(foo) 替换为 box::use(foo[...]) 即可使其正常工作。这是因为模块的范围很广,environment-aware.