You can add the environment as an attribute to defmacro :
defmacro <- function(..., expr, env = parent.frame()){ expr <- substitute(expr) a <- substitute(list(...))[-1]
Here we use new.env :
ifLen = defmacro(df, body1, body2 = {}, expr = { if(length(df) != 0) { body1 } else { body2 } }, env = new.env())
But here we do not have:
ifLetLen = defmacro(sym_str, x, body1, body2={}, expr = { stopifnot(is.character(sym_str)) stopifnot(length(sym_str) == 1) assign(sym_str, x) ifLen(eval(as.symbol(sym_str)), { body1 }, { body2 }) }) ifLetLen("..temp..", 1:3, {print(paste("true.", as.character(..temp..)))}, {print(paste("false.", as.character(..temp..))); xxx <- 69})
First example:
setna = defmacro(a, b, values, expr = {a$b[a$b %in% values] = NA; a}, env = new.env()) dat = data.frame(x = 1:4, y = rep(-9, 4)) > setna(dat, y, -9)
The problem with the proposed solution is that you have to take care of the environments (which shows which function and where the expressions are evaluated). I do not consider it very transparent as a programming tool.
Note. This does not solve the problem of local variables (from the original article) - it just puts everything in a separate environment (since typical R functions are all the same).