R:如果要在“过载”中使用`-`,如何使`-`运算符超载?码?

时间:2014-09-25 06:52:12

标签: r recursion overloading

为了好玩,我试图重载R中的-以便运行

some.string - n

会删除 some.string 并移除最后的 n 字符。

这是我在R

中的代码
`-` <- function(x,y) {
  minus <- force(`-`)
  if(typeof(x) == "character" & y >0) {
    return(substr(x,1,minus(nchar(x), as.integer(y))))
  } else {
    return(minus(x,y))
  }
}

"abc" - 2

然而,这似乎导致无限嵌套的递归。这是因为每次减去运行它都会尝试自行运行。但这正是我试图通过首先分配减去= -来阻止的?

如何避免这种无休止的递归?

4 个答案:

答案 0 :(得分:12)

您可以使用.Primitive("-")来避免无限循环。这应该有效:

`-` <- function(x,y) {
  if(typeof(x) == "character" & y >0) {
    return(substr(x, 1, nchar(x) - as.integer(y)))
  } else {
    .Primitive("-")(x, y)
  }
}

更接近您最初的想法是定义minus <- get("-", envir=baseenv())

`-` <- function(x,y) {
  minus <- get("-", envir=baseenv())
  if(typeof(x) == "character" & y >0) {
    return(substr(x,1,minus(nchar(x), as.integer(y))))
  } else {
    return(minus(x,y))
  }
}

答案 1 :(得分:3)

这是使用S4方法调度的另一种解决方案。与使用if-else结构相比,调度将更加优雅,您不必屏蔽原始函数-。但是对于原始函数,似乎不允许为原子数据类型定义方法。因此,我需要定义一个新类&#34; lastCharacters&#34;。实际上这使得最后一行更容易阅读,因为代码的意图是明确的......

lastCharacters <- setClass("lastCharacters", contains = "numeric")

setMethod("-", 
          signature(e1 = "character", e2 = "lastCharacters"),
          function(e1, e2) {
            substr(e1, 1, nchar(e1) - as.integer(e2))
          })

"abc" - lastCharacters(2)

答案 2 :(得分:2)

阴影回答是完全正确的,你问“只是为了好玩”,所以这没关系。但对于任何严肃的计划,我都会高度劝阻这些方法。以这种方式重载-将减慢程序中的每个减号操作,这种类型的黑客攻击可能会导致许多其他问题。

执行此类重载的简洁方法是引入自己的包装类,保存以重载运算符。例如:

specialstring <- 
  setRefClass("specialstring",
               fields = list(str = "character"),
               methods = list(
               initialize = function(str = character(0)) {
                 .self$str <- str
               },
               show = function() { print(.self$str) }
               )
  )

`-.specialstring` <- function(x, y) {
  if (class(x) == "specialstring" && is.numeric(y))
    return(substr(x$str, 1, nchar(x$str) - as.integer(y)))
  else
    stop("Incompatible types for -.specialstring")
}

现在,specialstring是一个字符串包装类,它具有所需的功能:

x <- specialstring("abc")
x - 1

运行正常,而x-x导致预期的错误消息。

如果你将这样的运算符重载(这是R中的OOP的思想,像igraph这样的包真的利用这个想法!)与阴影中的函数结合起来,那么x-x就不会导致上面的预期错误消息(Incompatible types for -.specialstring),但会导致误导消息Error in y > 0 : comparison (6) is possible...。当然,这可以通过-重载中的更多检查再次修复,但所有这些检查都是“糟糕的设计”,其中一个整洁的OOP解决方案是应该做的。

答案 3 :(得分:2)

根据@PatrickRoocks的建议,制作你自己的(S3或S4)类并在其上发送(而不是掩码)。

`-.my` = function(e1, e2) substr(e1, 1, nchar(e1) - e2)

x = c('all', 'the', 'world')
class(x) = 'my'
x - 1
## [1] "al"   "th"   "worl"
## attr(,"class")
## [1] "my"

另请参阅?基础(用于S3)或方法(S4)包中的操作,它定义了一组&#39;组通用&#39;

 Ops.my = function(e1, e2) {
     FUN = get(.Generic, envir = parent.frame(), mode = "function")
     substr(e1, 1, FUN(nchar(e1), e2))
}

实施(以无意义的方式,对于上面的特定功能 - substr(x, 1, nchar(x) + 2)没有意义),x - 1x + 1x / 2,在单一定义中。

S4版本(有点像@Sebastian,来自here)是

.My = setClass("My", contains="character")
setMethod("Arith", c("My", "numeric"), function(e1, e2) {
    substr(e1, 1, callGeneric(nchar(e1), e2))
})

> .My(c("all", "the", "world")) - 1
An object of class "My"
[1] "al"   "th"   "worl"