2015-12-08 37 views
2

在R中,我想創建一個類(R6Class),它在調用initialize時會創建很少的動態方法(方法的數量及其名稱取決於參數在初始化)。但是我遇到了一些與環境有關的奇怪問題在R6Class中創建動態方法,打印的魔力(ls.str())

這是一個不起作用的簡化版代碼。

library(R6) 

ffactory <- function(i) { 
    function() i 
} 

A <- R6Class(
    lock_objects=FALSE, 
    public=list(
    initialize=function(args) { 
     for (i in args) { 
     self[[i]] <- ffactory(i) 
     } 
    } 
) 
) 

a <- A$new(c('a', 'b', 'c')) 

現在:

> a$a() 
[1] "c" 
> a$b() 
[1] "c" 
> a$c() 
[1] "c" 

爲了找到什麼是錯的我補充說,在ffactory函數打印環境的線路。那就是

ffactory <- function(i) { 
    print(ls.str()) 
    function() i 
} 

現在它已經開始工作了!

> a$a() 
[1] "a" 
> a$b() 
[1] "b" 
> a$c() 
[1] "c" 

那麼爲什麼?應該有一些我不明白的東西。觀察者效應還是什麼? :)

print(ls.str())的魔法是什麼?其實我無法從這一行刪除printstr。有一條這樣的線路當然很愚蠢。更不用說屏幕上的垃圾了。

回答

3

您遇到過懶惰評估--R只要能夠在評估i之前等待 - 在前一種情況下,i將在所有實例中的最後一個值處進行評估。關於printls.str的組合沒有什麼特別的;任何強制i在您的方法調用(a$a(),a$b()等)之前都會進行評估。

形式上,這是force用於:

ffactory <- function(i) { 
    force(i); 
    function() i 
} 

R> a$a() 
#[1] "a" 
R> a$b() 
#[1] "b" 
R> a$c() 
#[1] "c" 

不過,這也正好做的工作:

ffactory <- function(i) { 
    #force(i); 
    .z <- capture.output(cat(i, "\n")) 
    function() i 
} 

R> a$a() 
#[1] "a" 
R> a$b() 
#[1] "b" 
R> a$c() 
#[1] "c" 

有可能是無數的方法來強制評估;但我認爲使用force會讓你的意圖最清楚。

報價直接的幫助文件,正式的說法

力力評價。如果參數將通過詞法範圍 規則在閉包中捕獲,並且稍後將在循環或應用函數中通過顯式分配或 隱式分配進行更改,則這可能很有用 。

,隨後,

這是語義糖:只要評估符號會做同樣的事情 (見例子)。

事實上,正在研究如何force定義,

R> force 
#function (x) 
# x 
#<bytecode: 0x3b7b528> 
#<environment: namespace:base> 

你甚至可以用逃脫

ffactory <- function(i) { 
    i; function() i 
} 

但如前所述,我認爲顯式調用force將會使你的代碼更具可讀性。

+0

呵呵呵。非常感謝!有趣的是,懶惰的參數'i'在惰性評估函數'function()i'內,它是一個非惰性評估函數。 – Bartek

+0

當然,如果它解決了您的問題,請隨時接受我的答案。 – nrussell