[英]In R, how do I define a function which is equivalent to `deparse(substitute(x))`?
I want to write a function in R which grabs the name of a variable from the context of its caller's caller. 我想在R中编写一个函数,该函数从调用者的调用者的上下文中获取变量的名称。 I think the problem I have is best understood by asking how to compose
deparse
and substitute
. 我认为我最好通过询问如何构成
deparse
和substitute
来理解这个问题。 You can see that a naive composition does not work: 您会发现幼稚的组合不起作用:
# a compose operator
> `%c%` = function(x,y)function(...)x(y(...))
# a naive attempt to combine deparse and substitute
> desub = deparse %c% substitute
> f=function(foo) { message(desub(foo)) }
> f(log)
foo
# this is how it is supposed to work
> g=function(foo) { message(deparse(substitute(foo))) }
> g(log)
log
I also tried a couple of variations involving eval.parent
but with no luck. 我还尝试了一些涉及
eval.parent
的变体,但是没有运气。 Any help is appreciated. 任何帮助表示赞赏。
Clarification : I'm not looking for a synonym for deparse(substitute(...))
, eg match.call()[[2]]
- what I'm looking for is a way to define a function 澄清 :我不是在寻找
deparse(substitute(...))
的同义词,例如match.call()[[2]]
-我正在寻找的是一种定义函数的方法
desub = function(foo) {
...
# What goes here?
}
such that the definition of f
above produces the same answer as g
. 这样上面
f
的定义产生与g
相同的答案。 It should look like this: 它看起来应该像这样:
> f=function(foo) { message(desub(foo)) }
> f(log)
log
Perhaps match.call
could be of use in the body of desub
above, but I'd like to know how. 也许
match.call
可能在上面的desub
主体中desub
,但我想知道如何使用。 Thanks! 谢谢!
As you surmised, this is an issue with environments. 如您所料,这是环境问题。 The reason why the function
f
does not give log
when you call f(log)
, is that the environment in which substitute
is called, namely the evaluation environment of desub
, does not contain a binding to log
. 为什么功能的原因
f
不给log
当你调用f(log)
,是环境中substitute
是所谓的,即评价环境desub
,不包含绑定log
。
The remedy is to evaluate the call to substitute
in the proper environment, and modify desub
accordingly: 补救措施是评估在适当的环境中进行
substitute
的调用,并相应地修改desub
:
desub <- function(x, env = parent.frame()) {
deparse(eval(substitute(substitute(x)), envir = env))
}
Now f
does what it was intended to do: 现在
f
完成预期的工作:
f(log)
#> log
Thanks to @egnha and @akrun for the brave attempts. 感谢@egnha和@akrun的勇敢尝试。 After playing around a bit I found a solution that works.
玩了一段时间后,我发现了一个可行的解决方案。
This fragment: 该片段:
desub <- function(y) {
e1=substitute(y)
e2=do.call(substitute,list(e1), env=parent.frame())
deparse(e2)
}
gives: 给出:
> f <- function(x) message(desub(x))
> f(log)
log
Update: 更新:
With help from Mark Bravington on the R-devel list, I was able to generalize this to multiple frames. 在R-devel列表上的Mark Bravington的帮助下,我能够将其推广到多个框架。 I thought I should post it here, because it's a bit more useful than the above, and because there was a tricky workaround involving (possibly buggy?) behavior in
parent.frame()
. 我认为我应该在这里发布它,因为它比上面有用,并且因为存在一个棘手的变通办法,涉及
parent.frame()
行为(可能是错误的? parent.frame()
。
# desub(v,0)=="v"
# desub(v,1)==deparse(substitute(v))
# desub(v,2)==name of v in grandparent's frame
# etc.
desub = function(y,n=1) {
env=environment();
for(i in 0:n) {
y = do.call(substitute, list(substitute(y)), env=env)
env = do.call(my_mvb_parent, list(), env=env)
}
deparse(y)
}
# helper:
#
# - using mvb.parent.frame fixes problems with capture.output and
# weird cycling behavior in the built-in parent.frame
#
# - this wrapper makes mvb.parent.frame not throw an error when we get
# to globalenv()
my_mvb_parent=function() {
library(mvbutils)
tryCatch(
mvb.parent.frame(2),
error=function(e) { globalenv()})
}
if(1) {
# example code
g2=function(t) {
for(i in 0:5) {
res=desub(t,i);
print(res);
res1=capture.output(desub(t,i))
stopifnot(capture.output(res)==res1)
}
}
g1=function(z) g2(z)
g=function(y) g1(y)
g(log)
# prints:
## [1] "t"
## [1] "z"
## [1] "y"
## [1] "log"
## [1] "log"
## [1] "log"
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.