簡體   English   中英

在R中,我如何定義一個等效於`deparse(substitute(x))`的函數?

[英]In R, how do I define a function which is equivalent to `deparse(substitute(x))`?

我想在R中編寫一個函數,該函數從調用者的調用者的上下文中獲取變量的名稱。 我認為我最好通過詢問如何構成deparsesubstitute來理解這個問題。 您會發現幼稚的組合不起作用:

# 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

我還嘗試了一些涉及eval.parent的變體,但是沒有運氣。 任何幫助表示贊賞。


澄清 :我不是在尋找deparse(substitute(...))的同義詞,例如match.call()[[2]] -我正在尋找的是一種定義函數的方法

desub = function(foo) {
    ...
    # What goes here?
}

這樣上面f的定義產生與g相同的答案。 它看起來應該像這樣:

> f=function(foo) { message(desub(foo)) }
> f(log)
log

也許match.call可能在上面的desub主體中desub ,但我想知道如何使用。 謝謝!

如您所料,這是環境問題。 為什么功能的原因f不給log當你調用f(log) ,是環境中substitute是所謂的,即評價環境desub ,不包含綁定log

補救措施是評估在適當的環境中進行substitute的調用,並相應地修改desub

desub <- function(x, env = parent.frame()) {
  deparse(eval(substitute(substitute(x)), envir = env))
}

現在f完成預期的工作:

f(log)
#> log

感謝@egnha和@akrun的勇敢嘗試。 玩了一段時間后,我發現了一個可行的解決方案。

該片段:

desub <- function(y) {
  e1=substitute(y)
  e2=do.call(substitute,list(e1), env=parent.frame())
  deparse(e2)
}

給出:

> f <- function(x) message(desub(x))
> f(log)
log

更新:

在R-devel列表上的Mark Bravington的幫助下,我能夠將其推廣到多個框架。 我認為我應該在這里發布它,因為它比上面有用,並且因為存在一個棘手的變通辦法,涉及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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM