Reputation: 2543
I have a function that may end up being nested (Inner
) and some other function (in general this function won't be known) that I'm calling Outer
, and I would like Inner
to be able to produce the same result regardless of the wrapper function (Outer
in the below case).
Inner <- function(x,baz,bang){
# code stuff things ...
x.prime = as.character(substitute(x))
return(c(x.prime,y,z))
}
Outer <- function(y){
Inner(y)
}
Inner(a)
# "a" "stuff" "things" , which is what I'm expecting, in particular the "a".
Outer(a)
# "y" .... , but I was expecting to get "a"?
Of course I'm not dead set on using substitute if someone knows of a better method.
Does anyone have any clues how to get Inner to output the same result regardless if it is nested or not?
thanks in advance.
Upvotes: 3
Views: 1088
Reputation: 52637
Here is a general outline that should help you solve your problem:
Inner <- function(x) {
my.call <- quote(substitute(x)) # we quote this here because we are going to re-use this expression
var.name <- eval(my.call)
for(i in rev(head(sys.frames(), -1L))) { # First frame doesn't matter since we already substituted for first level, reverse since sys.frames is in order of evaluation, and we want to go in reverse order
my.call[[2]] <- var.name # this is where we re-use it, modified to replace the variable
var.name <- eval(my.call, i)
}
return(var.name)
}
Outer <- function(y) Inner(y)
Outer2 <- function(z) Outer(z)
Now let's run the functions:
Inner(1 + 1)
# 1 + 1
Outer(2 + 2)
# 2 + 2
Outer2(3 + 3)
# 3 + 3
Inner always returns the outermost expression (you don't see y
or z
ever, just the expression as typed in .GlobalEnv
.
The trick here is to use sys.frames()
, and repeatedly substitute
until we get to the top level.
Note this assumes that all the "Outer" functions just forward their argument on to the next inner one. Things likely get a lot more complicated / impossible if you have something like:
Outer <- function(y) Inner(y + 1)
This code does not check for that type of issue, but you probably should in your code. Also, keep in mind that the assumption here is that your functions will only be called from the R command line. If someone wraps their functions around yours, you might get unexpected results.
Upvotes: 7