1

I am trying to write a function which would take as argument a function call, evaluates numeric args of this function call and then return corresponding character vector. This is what I have came up with:

ConvertToCharacter <- function(function.call) {
  call.str <- deparse(substitute(function.call))
  return(call.str)
}

> a <- 1
> ConvertToCharacter(sum(2, a))
"sum(2, a)"

> ConvertToCharacter(ddply(mtcars, .(vs), summarize, col=mean(cyl)))
"ddply(mtcars, .(vs), summarize, col = mean(cyl))"

Now, I want the numeric args to be evaluated before getting converted into a character vector. So that ConvertToCharacter(sum(2, a)) would return "sum(2, 1)" instead. I tried passing env=parent.frame() to subsitute but it won't work. Any idea how I could go with this?

Thanks!

hestoo
  • 13
  • 3

2 Answers2

0

You need to recursively inspect your call, evaluate the symbols, and sub in the values for the numeric ones like so:

ConvertToCharacter <- function(function.call, env=parent.frame()) {  
  call <- substitute(function.call)
  convert_recurse <- function(x, env) {
    if(is.call(x)) {
      return(as.call(lapply(x, match.fun(sys.call()[[1]]), env=env)))
    } else if (
      is.symbol(x) && 
      is.numeric(try(val <- eval(x, env), silent=TRUE))
    ) {
      return(val)
    } else {
      return(x)
    }    
  }
  deparse(convert_recurse(call, env))
}
a <- 1
ConvertToCharacter(sum(2, a))
lbsToKgs <- 2.2  
ConvertToCharacter(ddply(mtcars, .(vs), summarize, col=mean(cyl), wtkg=mean(wt * lbsToKgs)))

And this is what you get:

# [1] "sum(2, 1)"         
# [1] "ddply(mtcars, .(vs), summarize, col = mean(cyl), wtkg = mean(wt * "
# [2] "    2.2))"

Also, credit to Robert for the workaround the apply/Recall issue.

BrodieG
  • 51,669
  • 9
  • 93
  • 146
  • Excellent! Just curious as to why you are doing the match.fun. Why not simply `lapply(x, convert_recurse, env=env)` which appears to work? Thanks again for the brilliant solution! – hestoo Dec 30 '13 at 20:27
  • This way, if you rename the function at some point, you won't also have to update the inner code. Typically this is done with `Recall`, but that doesn't work here. – BrodieG Dec 30 '13 at 20:55
-1
ConvertToCharacter <- function(function.call) {
library(stringr)
str_replace(deparse(substitute(function.call)),"a",eval(a,envir=.GlobalEnv))
}

I hope it helps

Davide Passaretti
  • 2,741
  • 1
  • 21
  • 32