访问S4函数超类的插槽

3

我能否创建一个“function”的S4超类,并从函数调用中访问该对象的插槽?目前我有:

> setClass("pow",representation=representation(pow="numeric"),contains="function")
[1] "pow"
> z=new("pow",function(x){x^2},pow=3)
> z(2)
[1] 4

现在我真正想要的是函数自身的@pow次幂,因此如果我执行:

> z@pow=3 

我得到了立方体,如果我执行以下操作:

> z@pow=2

我得到了方块。

但是我不知道如何像在Python中那样获取对'self'的引用。我猜它在环境的某个地方...

下面是Python中的示例:

class Pow:
    def __init__(self,power):
        self.power=power
        self.__call__ = lambda x: pow(x,self.power)

p = Pow(2) # p is now a 'squarer'
print p(2) # prints 4

p.power=3 # p is now a 'cuber'
print p(2) # prints 8

这真的非常简单,我甚至不需要执行 "import antigravity"....



我认为你可能想使用一个引用类。 - hadley
“是吗?这次 S 语言终于正确实现了面向对象编程?” - Spacedman
如果你所说的“正确”是指已经以类似于Java等语言的方式实现,那么是的。 - hadley
我的意思是,S3的方式显然是错误的(但这是一个非常复杂的黑客),而S4只是不清楚地错误(见上文)。但是,我认为当t->Inf时,R->python...让我们从R中摆脱花括号并使用缩进.... - Spacedman
使用参考类,您将获得“self”,但会丢失Spacedman所要求的“isA”关系(至少在我的实验中是这样——是否有更完整的示例?)。此外,您的pow指数将具有引用语义,这可能会相当令人困惑,但与Python实现一致。 - Martin Morgan
但我认为我们不想要Python的可变语义。不可变性更加清晰易懂。 - hadley
3个回答

3

运用一些语言技巧

setClass("Pow", representation("function", pow="numeric"),
         prototype=prototype(
           function(x) {
               self <- eval(match.call()[[1]])
               x^self@pow
           }, pow=2))

然后

> f = g = new("Pow")
> g@pow = 3
> f(2)
[1] 4
> g(2)
[1] 8

尽管Spacedman说事情可能会出错,但请注意以下内容。
> f <- function() { Sys.sleep(2); new("Pow") }
> system.time(f()(2))
   user  system elapsed 
  0.002   0.000   4.005 

稍微偏离问题规格,但可能更加易于阅读的方法是:

setClass("ParameterizedFunFactory",
         representation(fun="function", param="numeric"),
         prototype=prototype(
           fun=function(x, param) function(x) x^param,
           param=2))

setGeneric("fun", function(x) standardGeneric("fun"))
setMethod(fun, "ParameterizedFunFactory",
          function(x) x@fun(x, x@param))

使用

> f = g = new("ParameterizedFunFactory")
> g@param = 3
> fun(f)(2)
[1] 4
> fun(g)(2)
[1] 8

我可能会给你那个。但是,如果你尝试创建一个匿名对象:new("Pow")(3),它实际上会从另一个由eval创建的新对象的@pow插槽中获取,而不是由初始的“new”调用创建的对象。虽然这并没有什么区别,但这是一件非常反常的事情。eval几乎总是有害的。 - Spacedman
颤抖。你让我的眼睛流血了。 - hadley

0

看起来可以通过 sys.function 访问父函数。

setClass("pow", slots = c(pow = "numeric"), contains = "function")
z <- new("pow", function (x) x^(sys.function()@pow), pow = 2)
z(6)
# [1] 36
z@pow <- 3
z(6)
# [1] 216

我不知道当初讨论这个问题时是否存在sys.function


0

我认为这取决于你真正想要什么。这个实现是否更接近你的目标?

setClass("pow",representation=representation(pow="numeric"),contains="function")
z=new("pow",function(x, pow=3){x^pow})
>  z(2)
[1] 8
 z(2,4)
#[1] 16

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接