基于语言的计算

上一节介绍了 R 中的函数式编程工具,理解了函数只是另外一种能够被传递的对象。当
建立一个新函数 fun( ) 时,也同时建立了一个与函数相关联的环境。这个环境被称做函
数的封闭环境,能够经过 environment(fun) 访问。每次调用该函数时,一个新的包含
还没有求值的实参(也称为 promise )的执行环境就会被建立,以支持函数的执行,这也是惰
性求值的基础。执行环境的父环境是函数的封闭环境,也是词法做用域的基础。
函数式编程容许咱们在高阶抽象层级上编写代码,元编程则更进一步。它容许咱们调
整语言自己,使特定的语言结构在特定状况下更方便使用。一些流行的 R 扩展包在其函数
中使用元编程以简化问题。本节将展现元编程的能力和它的优缺点,以便了解相关扩展包
和函数的工做方式。
在深刻了解其工做原理以前,咱们先看一些使用元编程的内置函数是如何使事情变得
简单的。
假设咱们想把内置数据集 iris 的每一个数值列中超过 80% 的项筛选出来。
标准方法是经过编写逻辑向量按行选取数据框子集:
iris[iris$Sepal.Length > quantile(iris$Sepal.Length, 0.8) &
iris$Sepal.Width > quantile(iris$Sepal.Width, 0.8) &
iris$Petal.Length > quantile(iris$Petal.Length, 0.8) &
iris$Petal.Width > quantile(iris$Petal.Width, 0.8), ]
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 110 7.2 3.6 6.1 2.5 virginica
## 118 7.7 3.8 6.7 2.2 virginica
## 132 7.9 3.8 6.4 2.0 virginica
上述代码中,每次调用 quantile( ) 函数,就给某列设置一个 80% 的阈值。代码能够运
行,但很是繁琐,由于每次使用一列数据,都要从 iris$开始,以上代码总共出现了 8 次 iris$。
内置函数 subset( ) 能够有效简化上述问题:
subset(iris,
Sepal.Length > quantile(Sepal.Length, 0.8) &
Sepal.Width > quantile(Sepal.Width, 0.8) &
Petal.Length > quantile(Petal.Length, 0.8) &
Petal.Width > quantile(Petal.Width, 0.8))
## Sepal.Length Sepal.Width Petal.Length Petal.Width Species
## 110 7.2 3.6 6.1 2.5 virginica
## 118 7.7 3.8 6.7 2.2 virginica
## 132 7.9 3.8 6.4 2.0 virginica
返回结果彻底相同,可是看起来更整洁。为何上述代码省略了 iris$依旧能够运行,
而前面代码省略了就不能运行呢?
iris[Sepal.Length > quantile(Sepal.Length, 0.8) &
Sepal.Width > quantile(Sepal.Width, 0.8) &
Petal.Length > quantile(Petal.Length, 0.8) &
Petal.Width > quantile(Petal.Width, 0.8), ]
## Error in `[.data.frame`(iris, Sepal.Length > quantile(Sepal.Length, 0.8)
& : 找不到对象'Sepal.Length'
这段代码不能正常运行,是由于 Sepal.Length 和其余列在计算子集表达式的域(或环境)
中没有定义。然而,subset( ) 函数使用元编程技术调整了其参数的计算环境,使表达式
Sepal.Length > quantile(Sepal.Length, 0.8) 在包含 iris 全部列的环境中被计算。
此外,subset( ) 不只适用于行的选取,也一样适用于列的选取。例如,咱们能够
直接将列名做为变量来指定 select 参数,而没必要使用字符向量:
subset(iris,
Sepal.Length > quantile(Sepal.Length, 0.8) &
Sepal.Width > quantile(Sepal.Width, 0.8) &
Petal.Length > quantile(Petal.Length, 0.8) &
Petal.Width > quantile(Petal.Width, 0.8),
select = c(Sepal.Length, Petal.Length, Species))
## Sepal.Length Petal.Length Species
## 110 7.2 6.1 virginica
## 118 7.7 6.7 virginica
## 132 7.9 6.4 virginica
如你所见,subset( ) 调整了它的第 2 个参数(subset)和第 3 个参数(select)
的计算方式。所以,咱们能够编写更精简的代码。
接下来的几个小节里,咱们将会学习代码背后的机制及其工做原理。html

捕获和修改表达式编程

执行表达式promise

非标准计算函数式编程

相关文章
相关标签/搜索