利用R语言词法作用域特性缓存数据

  R语言采用词法作用域(lexical scoping,或称静态作用域static scoping),关于作用域的相关说明可以参考Wiki,这里先举一个例子说明R语言词法作用域的特点。

  定义两个函数 g() 、 f() 以及一个变量 z 如下所示:

第1行定义变量 z 的值为10,而在函数 f() 中,再次定义 z 的值为20,此时调用 f(1) :

可见结果为31。执行 f(1) 时,由于函数 f() 中定义了 z 的值为20,故 y + z 的值为21,调用 g(21) 。在函数 g() 中,对于第4行的 x + z ,变量 z 没有在函数 g() 中定义,是一个自由变量(free variable),则继续在定义函数 g() 的作用域中寻找,由于第1行定义 z <- 10 ,此时认为在函数 g() 中 z 的值为10, g(21) 返回21+10 = 31,也就是 f(1) 的返回值。对于使用了词法作用域R语言,函数 g() 中自由变量 z 的值由定义 g() 的作用域决定。(对于动态作用域,函数中自由变量的值首先在调用函数的作用域中查找,此时f(1)的值应为41。)

  利用静态作用域的特性,可以将数据缓存在函数中,对于一些可能会对同一组数据调用多次的耗时计算,在第一次计算时将结果缓存下来,之后再使用相同的数据调用函数,则直接从缓存中读取结果直接返回。例如对于矩阵的求逆运算,实现如下:

函数 makeCacheMatrix() 中定义了用于缓存矩阵的逆的变量 i ,通过 setinverse() 和 getinverse() 进行赋值和读取。 setinverse() 和 getinverse() 中都没有定义变量 i ,它们使用的变量 i 都是  makeCacheMatrix() 中定义的 i 。函数 makeCacheMatrix() 根据输入的矩阵 x ,用于创建一个特殊的矩阵数据,包含矩阵的逆的缓存以及对应的设置和获取方法, cacheSolve() 计算矩阵的逆,并进行缓存:

输出为:

 可见第一次调用 cacheSolve(m) 时,计算、缓存并返回了矩阵的逆,第二次调用 cacheSolve(m) 则直接返回缓存中读取结果。