jhi*_*hin 16 design-patterns functional-programming r lazy-evaluation
"R通过了承诺,而不是价值观.承诺在首次评估时被强制执行,而不是在通过时.",请参阅G. Grothendieck的回答.另请参阅Hadley的书中的这个问题.
在简单的例子中
> funs <- lapply(1:10, function(i) function() print(i))
> funs[[1]]()
[1] 10
> funs[[2]]()
[1] 10
Run Code Online (Sandbox Code Playgroud)
可以考虑这种不直观的行为.
但是,我发现自己经常在日常发展过程中陷入这个陷阱.我遵循一个相当功能的编程风格,这意味着我经常有一个函数A返回一个函数B,其中B在某种程度上取决于调用A的参数.依赖性不像上面的例子那么容易看,因为计算很复杂并且有多个参数.
忽略这样的问题导致难以调试问题,因为所有计算都顺利进行 - 除了结果不正确.只有对结果的明确验证才能揭示问题.
最重要的是,即使我注意到这样的问题,我也不确定我需要哪些变量,哪些变量不需要force.
我怎样才能确保不陷入这个陷阱?是否有任何编程模式可以防止这种情况,或者至少确保我发现存在问题?
Bro*_*ieG 11
您正在使用隐式参数创建函数,这不一定是最佳实践.在您的示例中,隐式参数是i.另一种重做方式是:
library(functional)
myprint <- function(x) print(x)
funs <- lapply(1:10, function(i) Curry(myprint, i))
funs[[1]]()
# [1] 1
funs[[2]]()
# [1] 2
Run Code Online (Sandbox Code Playgroud)
在这里,我们通过使用显式指定函数的参数Curry.请注意,我们可以print直接使用咖喱,但这里没有用于说明目的.
Curry使用预先指定的参数创建函数的新版本.这使得参数规范明确,并避免了您遇到的潜在问题,因为Curry强制评估(有一个版本没有,但在这里没有帮助).
另一种选择是捕获父函数的整个环境,复制它,并使其成为新函数的父env:
funs2 <- lapply(
1:10, function(i) {
fun.res <- function() print(i)
environment(fun.res) <- list2env(as.list(environment())) # force parent env copy
fun.res
}
)
funs2[[1]]()
# [1] 1
funs2[[2]]()
# [1] 2
Run Code Online (Sandbox Code Playgroud)
但我不建议这样做,因为你可能会复制一堆甚至可能不需要的变量.更糟糕的是,如果你有嵌套的函数层来创建函数,这会变得更加复杂.这种方法的唯一好处是你可以继续你的隐式参数规范,但同样,这对我来说似乎是不好的做法.
正如其他人指出的那样,这可能不是R中最好的编程风格.但是,一个简单的选择就是养成强迫一切的习惯.如果你这样做,意识到你不需要实际调用force,只需要评估符号即可.为了减少丑陋,你可以尝试启动这样的函数:
myfun<-function(x,y,z){
x;y;z;
## code
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1395 次 |
| 最近记录: |