I'm digging my head into R's non-standard evaluation mechanisms. Halfway there, I'm still stuck from time to time. ;-)
I made a little calculator
that pretty-prints the calculation together with the result:
calculator <- function(e) cat(deparse(substitute(e)), "=", e)
This works fine:
calculator(1 + 2)
prints:
1 + 2 = 3
However, when calling the calculator
with:
a <- 1; b <- 2
calculator(a + b)
the output is:
a + b = 3
How can I tweak my calculator
in order it prints 1 + 2 = 3
also in the later case?
I tried:
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
This obviously doesn't work. After the lapply
call I have a list and cat
prints list(+, 1, 2)
to the console.
So I made another try:
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
..which is the same as my first version..
This works for an expression with one operator. For more complex expressions (which are nested function calls), you'll need to use recursion instead of the simple loops.
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