【发布时间】:2020-11-22 02:24:11
【问题描述】:
问题
我想检查 R 中的函数工厂是否“安全”。这里的“安全”意味着工厂创建的函数的结果仅取决于它们的参数,而不是全局变量。
说明
这是一个不安全的工厂:
funfac_bad = function(){
newfun = function()
return(foo)
return(newfun)
}
newfun 的返回值将取决于执行 newfun 时 foo 的值。如果 foo 恰好是未定义的,它甚至可能会发生错误。
现在 - 很明显 - 这个工厂可以通过将 foo 绑定到工厂内部的值来保证安全
funfac_good = function(){
foo = 4711
newfun = function()
return(foo)
return(newfun)
}
我认为我可以通过检查工厂中的全局变量来验证安全性。确实:
> codetools::findGlobals(funfac_bad)
[1] "{" "=" "foo" "return"
> codetools::findGlobals(funfac_good)
[1] "{" "=" "return"
但我的实际用例(非常)复杂。工厂的功能依赖于数百行代码的子函数和变量。因此,我获取了定义,我的工厂原则上如下所示:
funfac_my = function(){
sys.source("file_foo.R", envir = environment())
newfun = function()
return(foo)
return(newfun)
}
当且仅当在“file_foo.R”中执行的代码将名称“foo”绑定到一个值时,这是一个安全工厂。
但是(非常合乎逻辑)codetools::findGlobals 将始终将“foo”报告为全局变量。
问题
当定义来源时,如何检测此类函数工厂的不安全行为?
【问题讨论】:
-
显然你不能,因为
"file_foo.R"可能会在你检查的时间和你调用函数的时间之间发生变化。它不可能是安全的。 -
文件的更改不是问题,因为我可以检查并立即创建函数(或写保护文件或其他)。一旦创建,这些函数就会是安全的,因为它们独立于工厂。
-
为什么不在主体中使用
file_foo.R代码构建一个函数,然后检查一下?这仅意味着更改文件中的大约 5 行,以包含sys.source()调用之前和之后的内容。如果你知道file_foo.R不会改变,为什么不从一开始就把它放在函数中呢? -
是的,但在我的情况下,源文件包含嵌套函数/变量定义和数百行代码。简单地将所有这些倾倒到工厂中可能会让人难以理解。
标签: r function functional-programming namespaces