symbolrush
symbolrush

Reputation: 7457

Partially evaluate expression when doing non-standard evaluation in R

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..

Upvotes: 4

Views: 120

Answers (1)

Roland
Roland

Reputation: 132576

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

Upvotes: 6

Related Questions