【问题标题】:Programming with Reference Class参考类编程
【发布时间】:2013-09-11 21:37:24
【问题描述】:
  1. 如何定义几个多态构造函数和函数

    function Add( x, y : Integer ) : Integer;
    begin
        Add := x + y
    end;
    
    function Add( s, t : String ) : String;
    begin
        Add := Concat( s, t )
    end;
    
    begin
        Writeln(Add(1, 2));
        Writeln(Add('Hello, ', 'World!'));
    end.
    

我只能通过像这样的案例决定来做到这一点

A<-setRefClass(Class = "A"
              ,fields = list(var1="character")
              ,methods = list(setFields=A.setFields
                             ,initialize=function(var1) {
                                if(isClass(var1,"B"))
                                   .self$var1<-as.character(var1$getFields("var1"))                                  
                                else{
                                  .self$var1<-as.character(var1)
                                }
                                .self
                              })
)
  1. 如何将函数式编程与面向对象编程相结合。因此,如果我调用函数 getFields(vecB),其中 vecB 是一个向量或对象列表 B。返回应该是每个对象的值?

     B.getFields<-function(...,values){ 
       vars<-mget(names(.refClassDef@fieldClasses), envir = attr(.self, ".xData"))
       if(missing(values)) 
         return(vars)
       if(length(vars)==1)
         return(vars[[1]])
      return(vars[names(vars) %in% values])
      }
    
         B<-setRefClass(Class = "B"
                   ,fields = list(var1 = "character")
                     )
    
  2. 如何调试,例如函数从 A 类初始化?我试过了

    A$trace("initialize")
    a<-A$new("ABC")
    initial<-a$initialize
    trace(initial,browser,where=A)
    

    但它不起作用。

【问题讨论】:

    标签: r reference-class


    【解决方案1】:
    1. 使用 S4 泛型和方法实现多态性

      setGeneric("Add", function(x, y) standardGeneric("Add"))
      setMethod(Add, c("numeric", "numeric"), function(x, y) x + y)
      setMethod(Add, c("character", "character"), function(x, y) paste0(x, y))
      

      所以

      > Add(1, 2)
      [1] 3
      > Add("hello ", "world")
      [1] "hello world"
      > Add("hello ", 2)
      Error in (function (classes, fdef, mtable)  : 
        unable to find an inherited method for function 'Add' for signature '"character", "numeric"'
      

      在参考类中使用这个泛型的一个想法是

      A <- setRefClass("A",
          fields=list(x="ANY"),
          methods=list(
            getX=function() {
                .self$x
            }, setX=function(x) {
                .self$x <- x
                .self
            }, addX=function(y) {
                setX(Add(getX(), y))
            }, show=function() {
                cat("class:", class(.self), "\nx:", getX(), "\n")
            }))
      

      针对函数式程序样式进行适当的调度:

      setMethod(Add, c("A", "ANY"), function(x, y) x$addX(y))
      setMethod(Add, c("A", "A"), function(x, y) x$addX(y$getX()))
      

      (也许对于函数式编程,将$addX() 实现为A(.self, x=Add(x$getX(), y)) 更有意义,即创建x 的克隆?)以允许

      > Add(A(x=1), A(x=2))
      class: A 
      x: 3 
      > Add(A(x="hello "), "world")
      class: A 
      x: hello world 
      > A(x=2)$addX(3)
      class: A 
      x: 5 
      

      虽然不是A(x=1)$addX(A(x=2))

    2. 有关返回字段值的一种方法,请参阅 this answer

      B = setRefClass("B", fields=c(var1="list", var2="character"),
          methods=list(getFields=function(values) {
              flds = names(getRefClass()$fields())
              if (!missing(values))
                  flds = flds[flds %in% values]
              result = setNames(vector("list", length(flds)), flds)
              for (fld in flds)
                  result[[fld]] = .self[[fld]]
              result
          }))
      

      以函数方式调用的一种方式需要单独的实现,例如,

      setGeneric("getFields", function(x, ...) standardGeneric("getFields"))
      setMethod(getFields, "B", function(x, ...) x$getFields(...))
      setMethod(getFields, "list", function(x, ...) lapply(x, getFields, ...))
      
    3. 您的 A 类示例不完整。

      A <- setRefClass("A", methods=list(initialize=function(...) {
          message("hello A")
          callSuper(...)
      }))
      

      然后

      > A$trace("initialize", browser)
      Tracing reference method "initialize" for class "A"
      [1] "initialize"
      > A()
      Tracing .Object$initialize(...) on entry 
      Called from: eval(expr, envir, enclos)
      Browse[1]> n
      debug: {
          message("hello A")
          callSuper(...)
      }
      Browse[2]> n
      debug: message("hello A")
      Browse[2]> 
      

    【讨论】:

    • 1) 但是如何将Generic方法与Reference Classes结合起来,是否允许使用函数Add作为B类的成员函数? 2) 如何为函数式编程范例扩展getFields,我的意思是,将该函数用作引用类函数。因此,如果我通过 getFields(vecB,"var1") 调用该函数,其中 vecB 是 B 类对象的向量,它应该从每个对象返回 var1。这样它就可以像 R 中的所有其他函数一样工作。
    • @Heiko 我添加了一些想法;希望对您有所帮助。
    • 如果这样做是合法的,那么它会有所帮助,我也有类似的想法,但我是新手来决定我的想法是否有效。但是你的第一种方法读起来像一个无限循环setMethod(Add, c("A", "ANY"), function(x, y) x$addX(y)),但我直到现在还没有测试过,所以我想我还不明白。
    【解决方案2】:

    这是之前关于 R 中多态性的讨论:What are the suggested practices for function polymorphism in R?

    连接字符串的方法是粘贴。

    paste("Hello, ","world",sep="")
    

    【讨论】:

    • 或者paste0,如果您厌倦了每次都写出sep=""
    猜你喜欢
    • 1970-01-01
    • 2010-11-11
    • 1970-01-01
    • 2010-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多