2012-06-05 30 views
6

考慮這個功能a(),可打印出中傳遞參數:使用替代品()來獲取參數名,多層次最高

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 

工程。但是,當a()從另一個函數調用,它不再打印出原來的參數名:

,似乎工作是在另一個 substitute包裹
b <- function(y) { 
    a(y) 
} 

b("foo") 
# The input is y 

b(tmplist) 
# The input is y 

一種解決方案和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 

但這似乎不雅觀。如果我添加另一個層,它會失敗:

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

是否有一種很好的通用方法來獲取原始參數?

+0

我並不擅長處理環境,但我認爲或者使用'parent.frame'來玩kohske,或者指定一個全局變量是唯一的選擇。 R不會像c那樣通過引用傳遞。 –

回答

3

我不知道它這將在所有情況下工作得很好,但嘗試這個辦法:

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) 

然後,

> 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 
+0

這很不錯。但是,如果變量的名稱在兩個連續的步驟中是相同的,那麼我認爲在它真正完成之前,它會將其變爲停止狀態。假設你定義了f1和f2,所以他們把'xx'作爲參數 - 然後停在那裏。也許解決方案是保持循環,直到'i == sys.nframe()'。 – wch

+0

嗯,是的...如何解決...? – kohske

0

如何遞歸調用你的函數時

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

儘管這本身就是一個有趣的問題,但我想知道最好的解決方案是否合格變量名稱作爲一個字符,即用引號引起來。那麼這是沒有必要的。如果需要與該名稱相對應的對象,則可以使用getas.namedo.call來獲取對象,具體取決於您在該功能中的使用方式。

> 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 
+0

不幸的是,這種方法在我的應用程序中不起作用。我需要傳遞原始對象。所有這些的目的只是在出現錯誤時用輸入參數的名稱打印錯誤消息。 – wch

+0

嗯......我相信有一種方法可以「傳播」鏈上的錯誤,這樣一個被調用的函數中的錯誤將在頂層函數中觸發一條消息,在那裏你知道變量的「真實姓名」。有人比我更擅長使用'error'和'trycatch',可能會跳入此處。我們再次看到問正確問題的重要性! –

+1

@wch:爲了擴展卡爾的最後一條評論,正確的問題通常是關於你實際想要做什麼,而不是關於你如何去做。也就是說,不是「我如何用X來做Y?「或者更糟的是,」我該如何做X?「而是問」我該怎麼做Y?我試過X,但它不起作用。「 – Aaron

1

適應kohske的答案,這裏是一些作品,但不停止上升框架堆棧過早,如果變量有兩個連續的幀相同的名稱。我不知道它在所有情況下都能正常工作,但似乎能夠滿足我的需求。字符串與變量的引用與以前有所不同,但這對我的情況是可以的。

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