как выполнить итерацию внутри элементов запроса rlang в R

Итак, скажем, что я хочу сейчас, если X появится в запросе.

library(rlang)
library(purrr)
q <- quo(mean(X))

Я знаю, что могу проверить равенство с expr

q[[2]][[2]] == expr(X)
[1] TRUE

Но как мне повторить или сгладить элемент quo? flatten(q) не работает, я не мог использовать циклы for, не знаю, как использовать некоторую функцию карты из purrr.

В идеале я хотел бы захватывать X, когда это «данные», а не какая-либо функция.


person Bruno    schedule 01.10.2018    source источник


Ответы (1)


Я использую следующую пользовательскую функцию для преобразования выражений в их абстрактные синтаксические деревья (AST):

getAST <- function( ee ) { as.list(ee) %>% purrr::map_if(is.call, getAST) }

Поскольку вы работаете с запросами, существует промежуточный этап получения связанного выражения:

## Define a quosure
## Side note: don't use q as a variable name; it conflicts with q()
qsr <- quo( mean(5*X+2) )

## The associated expression
xpr <- rlang::get_expr( qsr )

## ...and its AST
ast <- getAST( xpr )
# List of 2
#  $ : symbol mean
#  $ :List of 3
#   ..$ : symbol +
#   ..$ :List of 3
#   .. ..$ : symbol *
#   .. ..$ : num 5
#   .. ..$ : symbol X
#   ..$ : num 2

Отсюда вы можете использовать стандартные методы, чтобы найти X. Например, сгладьте вложенный список и сравните каждый элемент с expr(X), как в вашем вопросе:

purrr::has_element( unlist(ast), expr(X) )
# [1] TRUE

purrr::map_lgl( unlist(ast), identical, expr(X) )
# [1] FALSE FALSE FALSE FALSE  TRUE FALSE
person Artem Sokolov    schedule 02.10.2018
comment
Это действительно круто! А как насчет того факта, что X, который я хочу захватить, не должен быть функцией? Это означает, что X будет частью окончательного списка (без какого-либо списка внутри) и что он не будет проиндексирован с помощью [[1]], верно? (Если я прав, как мне извлечь для этого только конечные списки?) - person Bruno; 02.10.2018
comment
Это немного сложнее. Во-первых, сами функции могут быть переданы в качестве аргументов другим функциям. Например, в summarize_at( mtcars, "wt", sum ) функция sum является аргументом для summarize_at и будет отображаться как конечный лист в AST. Во-вторых, сравните getAST( expr(X) ) и getAST( expr(X()) ). Они оба производят один и тот же AST, что делает невозможным отличить X от X(). Если вам интересно проверить, является ли что-то функцией или нет, я рекомендую использовать встроенный is.function(). - person Artem Sokolov; 02.10.2018