2013-11-03 91 views
3

我嘗試通過返回專用函數字典來創建一個函數工廠,或多或少地像函數式編程風格那樣。我嘗試在下面的代碼中執行此操作。R中的函數工廠

require(hash) 

names = c("aa","bb","cc"); 
funs = hash() 
for (i in seq(length(names))) { 
    n = names[i] 
    funs[[n]] = function(x) { 
    print(paste(n,":",x, sep="")) 
} 
} 

顯然,我有3個函數在數組中;但是,它們的行爲與迭代中的最後一個函數相同。

> funs[["aa"]](1) 
[1] "cc:1" 
> funs[["bb"]](2) 
[1] "cc:2" 
> funs[["cc"]](3) 
[1] "cc:3" 

我猜是R並沒有創造新的函數實例,但重複使用for循環中相同的函數對象。

我嘗試在希望R將創建不同的函數對象以下,

funs[[n]] = eval(parse(text="function(x) { print(paste(n,':',x, sep='')) }")) 

,但它的工作原理相同,第一個。

你知道如何創建一個創建不同函數對象的生成器嗎?

+0

我懷疑這是一個懶惰評估問題。 –

回答

8

根據哈德利的Advanced R Programmin, Lexical scoping,在功能funs[['aa']]funs[['bb']]身體可變n,和funs[['cc']]<environment: R_GlobalEnv>可變n

例如:

> funs[["aa"]](1) 
[1] "cc:1" 
> n <- "1234" 
> funs[["aa"]]("1") 
[1] "1234:1" 

做你想要什麼,我會寫一個返回函數的函數:

funs.gen <- function(n) { 
    force(n) 
    function(x) { 
    print(paste(n, ":", x, sep="")) 
    } 
} 

names = c("aa","bb","cc"); 
funs = hash() 
for (i in seq(length(names))) { 
    n = names[i] 
    funs[[n]] = funs.gen(n) 
} 

funs[["aa"]](1) 
funs[["bb"]](2) 
funs[["cc"]](3) 

注意force是問R值不要偷懶計算表達式n。如果將其刪除,則R將從for循環中評估n,這將產生與您的問題相同的結果。

+0

它的工作原理!感謝您的建議和參考。現在我瞭解到for循環中的function(){}確實創建了不同的函數實例。使用force()使不同的值與函數一起使用,以便函數可以獨立使用。 – user2949165

+1

+1不知道'force' –