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()の仕様のおかげ