R中的函数算子与函数包装

R中的函数算子与函数包装,r,functional-programming,dplyr,R,Functional Programming,Dplyr,Hadley的“”让我们简要了解了函数编程和“函数运算符”的可能应用。然而,我担心的是,我要么不完全理解这些方法是如何简化代码的,要么不愿意使用其他解决方案来遵循一些错误的做法 我没有创建期望输入是函数的运算符,而是创建了一个包装器,它将表达式作为参数,并返回完整的输出(而不是仍然需要调用的函数)。见示例: # function operator delay_by <- function(delay, f) { function(...) { Sys.sleep(delay)

Hadley的“”让我们简要了解了函数编程和“函数运算符”的可能应用。然而,我担心的是,我要么不完全理解这些方法是如何简化代码的,要么不愿意使用其他解决方案来遵循一些错误的做法

我没有创建期望输入是函数的运算符,而是创建了一个包装器,它将表达式作为参数,并返回完整的输出(而不是仍然需要调用的函数)。见示例:

# 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))