rlang::eval_tidy()と!!は違う
老害度が増してきているので、dplyrパッケージなどの裏側で使われている新しい"Rの評価"を与えるrlangパッケージについて勉強してた。
rlang::eval_tidy()と!!は違うんだなってことである。
まずはそれらのパッケージを読みこむ。
library("rlang") library("dplyr")
そして、以下のような関数を考える。
f <- function(x) { a <- rlang::enquo(x) print(a) dplyr::select(head(iris, 3), !! a) }
この辺は日本語だと以下の2資料が詳しい。
この関数は標準評価(所謂Standard Evaluation, SE)でも非標準評価(所謂None Standard Evaluation, NSE)でも動作する*1。
> f(Sepal.Width) <quosure: global> ~Sepal.Width Sepal.Width 1 3.5 2 3.0 3 3.2 > f("Sepal.Width") <quosure: empty> ~"Sepal.Width" Sepal.Width 1 3.5 2 3.0 3 3.2
一方、f()中の!!の箇所をrlang::eval_tidy()に置き換えた
g <- function(x) { a <- rlang::enquo(x) print(a) dplyr::select(head(iris, 3), rlang::eval_tidy(a)) }
を定義して同様に動かしてみると、、
> g(Sepal.Width) <quosure: global> ~Sepal.Width Show Traceback Rerun with Debug Error in overscope_eval_next(overscope, expr) : object 'Sepal.Width' not found > g("Sepal.Width") <quosure: empty> ~"Sepal.Width" Sepal.Width 1 3.5 2 3.0 3 3.2
となってNSEのほうは動かない。
これは!!が一枚(という表現でいいのか?)だけquoteした内容を剥がす一方、rlang::eval_tidy()は最後まで全部その場で評価しちゃうからなんだろうな、って思った。
まだ勉強中なので自信はない。
*1:これはselect()の仕様のおかげ