Skip to content
Prev 45713 / 63424 Next

as.name and namespaces

Hi Pat,

You could use substitute(), 
  > mycall <- quote(list(lm(Y ~ x1), lm(Y ~ x2)))
  > do.call("substitute", list(mycall, list(lm=quote(stats::lm))))
  list(stats::lm(Y ~ x1), stats::lm(Y ~ x2))
The do.call is necessary because substitute() does not evaluate
its first argument and we want 'mycall' evaluated to become
the call to list(...) before substitute works on it.

substitute replaces all instances of a name in an expression.
bquote lets you be more selective (only names in .() get replaced):
  > mycall2 <- quote(list(lm(Y ~ x1), .(lm)(Y ~ x2)))
  > do.call("bquote", list(mycall2, list(lm=quote(stats::lm), list=quote(base::list))))
  list(lm(Y ~ x1), stats::lm(Y ~ x2))
   
S+'s substitute() has an evaluate=FALSE/TRUE argument to control
whether its first argument is evaluated thus letting you avoid  do.call():
  S+>  mycall <- quote(list(lm(Y ~ x1), lm(Y ~ x2)))
  S+> substitute(mycall, list(lm=quote(stats::lm)), evaluate=TRUE)
  list(stats::lm(Y ~ x1), stats::lm(Y ~ x2))

It is much harder if you want to find and replace expressions more general
than name, e.g., changing "stats::lm" to "lm" or "log(x+1)" to "logp1(x)" .
package::codetools and package::compiler might help.  I have used rapply()
in S+ for this sort of thing but R's rapply() does not work on functions:
  S+> f <- function(x, y) exp(log(x+1) + log(abs(y)+1) + log(z))
  S+> fNew <- rapply(f, how="replace", classes="call",
       function(e) {
         if (identical(e[[1]], quote(log)) && is.call(logArg <- e[[2]])) {
            if (identical(logArg[[1]], quote(`+`)) && identical(logArg[[3]], 1)) {
               e <- call("logp1", logArg[[2]])
            }
         }
         e
       })
  S+> fNew
  function(x, y)
  exp(logp1(x) + logp1(abs(y)) + log(z))
The is pretty ugly code but it did help us quickly install optimizations in
a large mass of code.

Bill Dunlap
Spotfire, TIBCO Software
wdunlap tibco.com