3

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

2
  • 1
    Could you provide some details about what you're trying to accomplish here? Commented Oct 24, 2014 at 23:34
  • This code is helpful for simple translations to another programming language, essentially I want to see if I don't have to force the users to use double quotes. Commented Oct 24, 2014 at 23:40

1 Answer 1

7

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for the working solution as well as the thorough explanation.
I'm not sure if your above limitation is true. I've tried (with your def of Inner) Outer<-function(y) Inner(y+1); Outer2<-function(z) Outer(z+5) and for Outer2(r) I get r + 5 + 1 (with type language ). Maybe I misunderstood your note?
@csta, it may not be a limitation. I hadn't tested it, but was concerned it might not work. Looks like it isn't based on your test.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.