【发布时间】:2015-05-19 00:03:12
【问题描述】:
“R 传递 promises,而不是值。承诺在第一次评估时被强制执行,而不是在传递时。”,参见 G. Grothendieck 的 this answer。另请参阅 this question 指的是 Hadley 的书。
在简单的例子中,例如
> funs <- lapply(1:10, function(i) function() print(i))
> funs[[1]]()
[1] 10
> funs[[2]]()
[1] 10
可以考虑这种不直观的行为。
但是,我发现自己在日常开发过程中经常陷入这个陷阱。我遵循一种相当函数式的编程风格,这意味着我经常有一个函数 A 返回一个函数 B,其中 B 在某种程度上取决于调用 A 的参数。依赖关系不像上面的例子那么容易看出,因为计算复杂并且有多个参数。
忽略这样的问题会导致难以调试的问题,因为所有计算都运行顺利 - 除了结果不正确。只有对结果的明确验证才能揭示问题。
最重要的是,即使我注意到了这样的问题,我也永远无法确定 force 需要哪些变量,哪些不需要。
我怎样才能确保不落入这个陷阱?是否有任何编程模式可以防止这种情况发生,或者至少确保我注意到存在问题?
【问题讨论】:
-
似乎这可能是一个重新评估您的编程风格的好机会,如果您强迫您正在使用的语言做一些它本来就没有设置做的事情......跨度>
-
...这就是为什么我要寻找能够规避这个问题的模式。 ;-)
-
这个问题仍然具有历史意义,但今天的读者可能有兴趣知道,从 R 3.4.1(可能早在 3.2.0)开始,OPs 帖子中的示例引起了乐趣[[5 ]]() 生成
5。 -
@russellpierce 确实如此(并且确实在 R 3.2.0 中进行了更改),但它并没有使这个问题过时。唯一改变的(据我所知)是基础 R 中的高阶函数,例如
lapply和Reduce现在自动force它们的参数。惰性求值原则仍然存在,因此这不会改变自定义函数的任何内容。根据下面提供的答案,正确的解决方案似乎是在自定义高阶函数中始终使用force函数参数,或者使用提供的机制,例如lapply或Curry。 -
@jim 感谢您的上下文。那么,今天该问题的重现会是什么样子?
标签: r design-patterns functional-programming lazy-evaluation