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

Consider this function a() , which displays the argument that was passed:

 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 

It works. But when a() is called from another function, it no longer prints 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 port to other substitute and 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 it 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?

+6
source share
4 answers

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

 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 
+3
source

Although this is an interesting question in itself, I am wondering if it is better to simply pass the variable name as a symbol, i.e. in quotation marks. Then none of this is needed. If an object matching the name is needed, it can be obtained using get or as.name and do.call , depending on how you use it inside the function.

 > f0 <- function(x) {message("The input is ", x)} > f1 <- function(.f1) f0(.f1) > f2 <- function(.f2) f1(.f2) > f2("aa") The input is aa > f1("bb") The input is bb > f0("cc") The input is cc 
+1
source

The kohske adaptation responds, here's something that works, but doesn't stop popping up in the frame stack prematurely if the variable has one name in two consecutive frames. I don’t know if it works correctly in all situations, but it seems that it is coping with my needs. Quoting strings and variables is slightly different from the previous ones, but this is normal for my case.

 a <- function(x) { newname <- substitute(x) # Travel up the frame stack until we hit the top. for(i in seq_len(sys.nframe())) { oldname <- do.call("substitute", list(as.name(newname), parent.frame(i))) newname <- oldname } message("The input is ", deparse(newname)) } b <- function(y) a(y) c <- function(z) b(z) a("adsf") # The input is adsf a(foo) # The input is foo b("adsf") # The input is adsf b(foo) # The input is foo c("adsf") # The input is adsf c(foo) # The input is foo 
+1
source

How about recursively calling your function when

 deparse(substitute(x))!=deparse(eval(substitute(substitute(x)), parent.frame()) 
0
source

Source: https://habr.com/ru/post/917413/


All Articles