Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using substitute() to get argument names, multiple levels up

Tags:

r

Consider this function a(), which prints out the argument that was passed in:

a <- function(x) {
  message("The input is ", deparse(substitute(x)))
}

a("foo")
# The input is "foo"

tmplist <- list(x1 = 1, x2=2)
a(tmplist)
# The input is tmplist

That works. But when a() is called from another function, it no longer prints out the original argument names:

b <- function(y) {
  a(y)
}

b("foo")
# The input is y

b(tmplist)
# The input is y

One solution that seems to work is to wrap in another substitute and an eval:

a1 <- function(x) {
  message("The input is ", deparse(eval(substitute(substitute(x)), parent.frame())))
}

a1("foo")
# The input is "foo"

tmplist <- list(x1 = 1, x2=2)
a1(tmplist)
# The input is tmplist

b1 <- function(y) {
  a1(y)
}

b1("foo")
# The input is "foo"

b1(tmplist)
# The input is tmplist

But this seems inelegant. And it fails if I add another layer:

c1 <- function(z) {
  b1(z)
}
c1("foo")
# The input is z

Is there a good, general way to get the original argument?

like image 441
wch Avatar asked Jun 05 '12 07:06

wch


1 Answers

I'm not sure it this will work well in all situations, but try this:

f0 <- function(x) {
  nn <- substitute(x)
  i <- 1
  while(TRUE) {
    on <- do.call("substitute", list(as.name(nn), parent.frame(i)))
    if (on == nn) break;
    nn <- on
    i <- i + 1
  }
  message("The input is ", nn)
}

f1 <-function(.f1) f0(.f1)
f2 <- function(.f2) f1(.f2)

and then,

> f2(foo)
The input is foo
> f1(poo)
The input is poo
> f0(moo)
The input is moo
> f2(";(")
The input is ;(
> f1(":)")
The input is :)
> f0(":p")
The input is :p
like image 100
kohske Avatar answered Sep 23 '22 02:09

kohske