Развернуть вызов, сохраненный в переменной, перед передачей в функцию - PullRequest
2 голосов
/ 19 марта 2020

У меня есть вызов, хранящийся в переменной. При необходимости вызов происходит по односторонней формуле:

f <- ~ a + b
rhs <- rlang::f_rhs(f)
rhs
#> a + b

Создано в 2020-03-19 с помощью пакета prex (v0.3.0)

Теперь формула может содержать bquote стиль, экранирующий .(), и я хочу получить все экранированные имена.

Глядя на исходный код bquote, я создал эта функция:

escapedNames <- function (expr, where = parent.frame()) 
{
    unquote <- function(e) {
        if (is.pairlist(e)) {
            NULL
        } else if (length(e) <= 1L) {
             NULL
        } else if (e[[1L]] == as.name(".")) {
            deparse(e[[2L]])
        } else {
            x <- sapply(e, unquote)
            unlist(x)
        }
    }
    unquote(substitute(expr))
}

escapedNames(a + .(b) + c)
#> [1] "b"

Как видите, она прекрасно работает для жестко закодированных выражений. Однако я не могу понять, как передавать вызовы, хранящиеся в переменных.

f <- ~ a + .(b)
rhs <- rlang::f_rhs(f)
escapedNames(rhs)
#> NULL

Это, конечно, имеет смысл, поскольку escapedNames обрабатывает все, что ему дано, как вызов, который я хочу проанализировать, так что он не знает, чтобы расширить rhs, прежде чем искать имена.

Итак, как я могу решить эту проблему?

1 Ответ

3 голосов
/ 23 марта 2020

Сразу после публикации щедрости я нашел способ сделать это, но, пожалуйста, покажите мне лучший способ!

Мы можем использовать eval и rlang::expr для принудительного расширения переменной формулы перед оценкой escapedNames:

escapedNames <- function (expr) 
{
    unquote <- function(e) {
        if (is.pairlist(e) || length(e) <= 1L) NULL
        else if (e[[1L]] == as.name("."))      deparse(e[[2L]])
        else                                   unlist(sapply(e, unquote))
    }
    unquote(substitute(expr))
}

formula <- ~ a + .(b) + c + .(d)
rhs <- rlang::f_rhs(formula)

eval(rlang::expr(escapedNames(!!rhs)))
#> [1] "b" "d"

Создано в 2020-03-23 ​​с помощью представительного пакета (v0.3.0)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...