2015-07-21 62 views
1

我試圖創建一個引用從它被調用來創建一個唯一的ID範圍的函數:R - 如何從被調用的函數中找到調用函數的環境?

uniqueid <- function(name, envir = NULL) { 

    if(identical(envir, globalenv())) { 
    e = envir 
    } else if (is.null(envir)) { 
    e = parent.frame() 
    } else if (is.environment(envir)) { 
    e = envir 
    } else { 
    stop("given non-default argument \'envir\' is not an environment") 
    } 

    return(paste(sep = "", 
    sub('<environment: (.*)>', '\\1', capture.output(e)), 
    ".", 
    name 
    ) 
) 
} 

我能做些什麼,使這項工作,我認爲它應該工作的方式嗎?者繼續在返回其定義的功能範圍,而不是在那裏進行評估:

hello <- new.env() 
hello$env <- new.env() 

eval(envir=hello$env, { 
    print(environment()) 
    print(hello$env) #hello$env is an environment 
    print(hello) #hello is an environment 
    uniqueid('hi') 
}) 

我試圖讓這些至少一個投其所好,但它似乎並不像它想上班。 R或者返回全局環境,或者爲函數調用實例創建的臨時框架/環境的範圍不斷變化。該ID需要在多個呼叫之間重現並取決於環境。

我知道我可以通過環境,但我開始懷疑是否做主叫的環境中捕捉實際上是可能的。

+0

什麼是'hello'?它是'hello < - new.env(); hello $ env < - new.env()'? –

+0

@ mathematical.coffee兩者!我試圖在嵌套環境中查看它是否存在多少環境問題,但與此無關。 – VermillionAzure

+1

你舉的例子是不可複製的 - 不能創建'hello'和'parent.frame'需要'N'作爲參數,而不是環境,或者你會得到一個錯誤。 –

回答

3

TL,DR:parent.frame()parent.frame(environment()); evalq不是eval

parent.frame以參數n爲代數回去,而不是environment()調用(這是一個環境)的結果。如果您將其撥出parent.frame(),則表示您沒有問題。

而且,夜示例代碼並不像您期望的,因爲你的environment()命令在調用被評估爲eval,被評價爲eval部分之前的工作。即你必須引用你的論點eval。或者,使用evalq而不是eval

E.g.

uniqueid <- function(name) { 
    print(parent.frame()) 
} 
hello <- new.env() 
hello$env <- new.env() 
evalq(envir=hello$env, { 
    print(environment()) # prints hello$env 
    print(hello$env)  # prints hello$env 
    print(hello)   # prints hello 
    uniqueid('hi')  # prints hello$env 
}) 

例如,這將獲得環境ID並將其添加到name

uniqueid <- function(name) { 
    # GlobalEnv etc have names; hello doesn't 
    envName <- environmentName(parent.frame()) 
    # get the environment ID from the parent.frame() output if no name 
    if (envName == "") { 
     p <- parent.frame() 
     envName <- sub('<environment: (.*)>', '\\1', capture.output(p)) 
    } 
    return(paste(envName, name, sep=':')) 
} 
uniqueid('x') # R_GlobalEnv:x 
print(hello) # <environment: 0x4641fa0> 
evalq(envir=hello, uniqueid('x')) # "0x4641fa0:x" 
print(hello$env) # <environment: 0x4640e60> 
evalq(envir=hello$env, uniqueid('x')) # "0x4640e60:x" 
+0

我認爲這裏的關鍵問題是,我不明白它插入範圍之前被評估的表達。謝謝! – VermillionAzure

2

您的問題是eval()期待的東西,是不計算。通過傳遞代碼塊{},您不會阻止評估。例如,考慮簡單的情況

a<-10 
ee<-new.env() 
ee$a<-5 

eval(envir=ee, a) 
# [1] 10 
eval(envir=ee, {a}) 
# [1] 10 
eval(envir=ee, quote(a)) 
# [1] 5 
evalq(envir=ee, a) 
# [1] 5 

通知最後兩個如何明確地引用表達式,或者使用evalq()做表達的報價。這些允許評估延遲到在要求的環境內執行。

所以,如果你只需要改變你的eval()evalq(),你應該罰款。