基於語言的計算

上一節介紹了 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

非標準計算函數式編程

相關文章
相關標籤/搜索