Я копаюсь в нестандартных механизмах оценки R. На полпути я все еще время от времени застреваю. ;-)
Я сделал небольшой calculator
, который красиво печатает расчет вместе с результатом:
calculator <- function(e) cat(deparse(substitute(e)), " = ", e)
Это отлично работает:
calculator(1 + 2)
печатает:
1 + 2 = 3
Однако при вызове calculator
с помощью:
a <- 1; b <- 2
calculator(a + b)
вывод:
a + b = 3
Как я могу настроить свой calculator
, чтобы он печатал 1 + 2 = 3
и в последнем случае?
Я старался:
calculator2 <- function(e) {
ex <- lapply(substitute(e), function(x) ifelse(is.numeric(x), eval(x), x))
cat(deparse(ex), " = ", e)
}
calculator2(1 + 2)
# list(+, 1, 2) = 3
calculator2(a + b)
# list(+, a, b) = 3
Это явно не работает. После вызова lapply
у меня есть список, и cat
выводит list(+, 1, 2)
на консоль.
Итак, я сделал еще одну попытку:
calculator3 <- function(e) {
ex <- substitute(e)
for(i in 1:length(ex)) {
if (is.numeric(ex[[i]])) ex[[i]] <- eval(ex[[i]])
}
cat(deparse(ex), " = ", e)
}
calculator3(1 + 2)
# 1 + 2 = 3
calculator3(a + b)
# a + b = 3
..то же, что и моя первая версия ..
@ Роланд: Спасибо. Я понял это в тот момент, когда понял ваше решение. :-)
Это работает для выражения с одним оператором. Для более сложных выражений (которые представляют собой вложенные вызовы функций) вам нужно будет использовать рекурсию вместо простых циклов.
a <- 1; b <- 2
calculator1 <- function(e) {
expr <- substitute(e)
evalexpr <- lapply(expr, eval) #evaluate each part of expression
numind <- vapply(evalexpr, is.numeric, FUN.VALUE = logical(1))
expr[numind] <- evalexpr[numind]
cat(deparse(expr), " = ", e)
}
calculator1(a + b)
#1 + 2 = 3
calculator1(1 + 2)
#1 + 2 = 3
Твоя третья попытка была близка. Вам нужно только
eval
перед тестированием числовых значений. В противном случаеa
иb
остаются символами в выражении.