7

refclasses (R5) を忘れて R6 に移行しようとしていますが、動的コードに問題があります。新しい関数を追加すると、R5 で動作します。

clsTrn <- setRefClass("clsTrn",
  fields = list(x = "numeric"),
  methods = list(
    add_function = function(rcode) {
      eval(parse(text=rcode), envir=.self)
    }
  )
)  

cls <- clsTrn$new(x=4)
cls$x
# [1] 4
cls$add_function("predict = function(y) {return(.self$x*y)}")

cls$predict(3) 
#[1] 12

同様のコードは R6 では機能しません。

library(R6)

clsTrnR6 <- R6Class("clsTrnR6",
  lock=FALSE,
  public = list(
    x = NA,
    initialize = function(x) {
      self$x <- x
    },
    add_function = function(rcode) {
      eval(parse(text=rcode), envir=self)
    }
  )
)  


clsR6 <- clsTrnR6$new(x=4)
clsR6$x
#[1] 4

clsR6$add_function("predict = function(y) {return(self$x*y)}")
# Błąd weval(expr, envir, enclos) : nie udało się znaleźć funkcji '='
clsR6$predict(3)

クラス定義に予測を追加しても何も変わらず、同じエラーが発生します。 解決策はありますか?前もって感謝します。

> sessionInfo()
R version 3.1.1 (2014-07-10)
Platform: x86_64-pc-linux-gnu (64-bit)

locale:
 [1] LC_CTYPE=pl_PL.UTF-8       LC_NUMERIC=C               LC_TIME=pl_PL.UTF-8        LC_COLLATE=pl_PL.UTF-8     LC_MONETARY=pl_PL.UTF-8   
 [6] LC_MESSAGES=pl_PL.UTF-8    LC_PAPER=pl_PL.UTF-8       LC_NAME=C                  LC_ADDRESS=C               LC_TELEPHONE=C            
[11] LC_MEASUREMENT=pl_PL.UTF-8 LC_IDENTIFICATION=C       

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] R6_2.0

loaded via a namespace (and not attached):
[1] codetools_0.2-8 rpart_4.1-5     tools_3.1.1    
> 

追加: @G.Grothendieck の素晴らしい回答の後、文字列ベースの関数定義がありますが、もっとエレガントなソリューションがあるかもしれません。

library(R6)

clsTrnR6 <- R6Class("clsTrnR6",
  lock=FALSE,
  public = list(
    x = NA,
    initialize = function(x) {
      self$x <- x
    },
    add_function = function(name, meth) {
      self[[name]] <- meth
      environment(self[[name]]) <- environment(self$add_function)
    },
    add_function2 = function(name, meth) {
      eval(parse(text=paste0("predict <- ",meth)))
      self[[name]] <- predict
      environment(self[[name]]) <- environment(self$add_function)
    }
  )
)  

clsR6 <- clsTrnR6$new(x=4)
clsR6$x

#[1] 4

clsR6$add_function2("predict", "function(y) y*self$x")
clsR6$predict(11)

#[1] 44
4

3 に答える 3

6

これを試して。参照クラスの例と同様に、(クラスではなく) オブジェクトに関数を追加します。以下nameは、関数/メソッドの名前を含む文字列でありmeth、関数/メソッド自体です。

clsTrnR6 <- R6Class("clsTrnR6",
  lock=FALSE,
  public = list(
    x = NA,
    initialize = function(x) {
      self$x <- x
    },
    add_function = function(name, meth) {
      self[[name]] <- meth
      environment(self[[name]]) <- environment(self$add_function)
    }
  )
)  
clsR6 <- clsTrnR6$new(x=4)
clsR6$x
#[1] 4
clsR6$add_function("predict", function(y) y*self$x)
clsR6$predict(11)
## 44

これもprotoを使用して簡単に実行できることに注意してください。特別な必要はありませんadd_function。クラスの役割を果たすプロト オブジェクト (プロト ビネットでは「トレイト」と呼ばれます) を示すために大文字を使用し、インスタンスの役割を果たすプロト オブジェクトを示すためにP小文字を使用します。p

library(proto)

P <- proto(new = function(., x) proto(x = x))
p <- P$new(x = 4)

p$predict <- function(., y) .$x * y
p$predict(11)
## 44

.プロトでオブジェクトを参照するために使用するのが一般的ですが、必要に応じて名前self(または任意の名前) を代わりに使用.できます。

于 2014-10-13T02:49:14.590 に答える
5

$set() methodジェネレーターオブジェクトで使用できます。したがって、オブジェクトではなくクラス定義を変更します。

clsTrnR6$set("public", "predict", function(y) self$x*y)
clsR6 <- clsTrnR6$new(x=4)
clsR6$predict(3)
[1] 12

編集:

クラス定義を変更すると、$set 修飾子を使用する前に作成されたオブジェクトにはpredict関数がなくなります。

于 2014-10-13T00:34:25.527 に答える