9 函数式编程

9.1 闭包

即由函数编写的函数,它将父函数的环境封装并可以访问它的所有变量,这允许我们使用两个层次的参数,父层次可以控制运算,子层次可以进行工作。

9.1.1 例1

power <- function(exponent) {
  function(x) {
    x ^ exponent
  }
}
square <- power(2)
cube <- power(3)

square()cube()即两个闭包,闭包内的子函数采用匿名函数的方法去写,查看子函数环境内容的方法有两种:

as.list(environment(square))
#> $exponent
#> [1] 2

pryr::unenclose(square)
#> function (x)
#> {
#>     x^2
#> }

9.1.2 例2

new_counter <- function() {
  i <- 0
  function() {
    i <<- i + 1
    i
  }
}
count_one <- new_counter()

上面这个例子中的new_counter()函数的执行环境就是闭包count_one()函数的封闭环境,即就是闭包的封闭环境中实际上是有变量i的初始值的,通过强赋值号<<-来实现修改父环境中的对象(执行环境的父环境是封闭环境和调用环境,但R的词法作用域法则只使用封闭父环境),每次运行闭包,它封闭环境中的变量i被改变并保存,从而实现了维持计数。

上面看似实现了一个可变对象,但因为R的每次修改都是“复制后修改”,所以如果确实需要可变对象,且不是小型工程,最好使用参考类(RC)去实现。

9.2 编译优化

函数最好都使用字节码编译器编译一遍,速度大概会提升5% ~ 10%

compiler::cmpfun()