R中的函数算子与函数包装
Hadley的“”让我们简要了解了函数编程和“函数运算符”的可能应用。然而,我担心的是,我要么不完全理解这些方法是如何简化代码的,要么不愿意使用其他解决方案来遵循一些错误的做法 我没有创建期望输入是函数的运算符,而是创建了一个包装器,它将表达式作为参数,并返回完整的输出(而不是仍然需要调用的函数)。见示例:R中的函数算子与函数包装,r,functional-programming,dplyr,R,Functional Programming,Dplyr,Hadley的“”让我们简要了解了函数编程和“函数运算符”的可能应用。然而,我担心的是,我要么不完全理解这些方法是如何简化代码的,要么不愿意使用其他解决方案来遵循一些错误的做法 我没有创建期望输入是函数的运算符,而是创建了一个包装器,它将表达式作为参数,并返回完整的输出(而不是仍然需要调用的函数)。见示例: # function operator delay_by <- function(delay, f) { function(...) { Sys.sleep(delay)
# function operator
delay_by <- function(delay, f) {
function(...) {
Sys.sleep(delay)
f(...)
}
}
# simple wrapper
delay_by2 <- function(expr, delay) {
Sys.sleep(delay)
eval(expr)
}
delay_by(1, sqrt)(2)
delay_by2(sqrt(2), 1)
operator <- delay_by(1, sqrt)
wrapper <- function(x) delay_by2(sqrt(x), 1)
operator(2)
wrapper(2)
此解决方案的潜在缺点是,它不会创建持久执行环境来存储维护函数状态的变量,但可以使用
- 软件工程的一个重要方面是功能简单
要测试和打包,表达式就没有那么多了。所以如果你使用
函数方法您可以编写单元测试,并将其放入一个包中。
使用eval方法,您仅限于自己的REPL测试。显然,我们都应该进行“测试驱动的开发”,至少在我们的产品代码上是这样,任何东西都不应该被淘汰
没有一组单元测试,覆盖了尽可能多的代码
经济上可行。这使人们的生活更加轻松
(包括你)有一天可能需要做出改变的人
- 还请注意,编译器优化可能可以在函数范围内完成,但不能在表达式上完成。那是真的
在其他语言中,但我对R的编译器是如何工作的知之甚少
我想说些什么
- 我想到的另一点是,eval路由并不是真正可伸缩的,也就是说,它只适用于高达
一定的复杂性。另一方面,使用函数允许
逻辑发展到任何实际规模
- 最后,
eval
作为一种构造是一种非常强大的构造,但它会给你带来麻烦,有点像使用高功率激光器
剪纸。因为它通常很容易实现,所以它存在于许多应用程序中
网络上有很多关于为什么它是危险的文章,你应该看看它们。所以像那个高功率激光器一样,你不应该
习惯于使用它,除非有必要
评估方法不允许预洗。可以想象,它也可以用于代码注入场景。但是这些都是非生产代码的小问题。关于安全问题-我说的对吗,如果函数运算符不执行检查,如果提供的函数是白名单的,那么eval()
没有任何好处?实际上,如果您使用的是eval(,,,)
,而不是eval(parse(…)
,也许我的反对意见不成立。
lapply(1:10, function(x) sqrt(x) %>% delay_by2(1))