为了好玩,我试图重载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
然而,这似乎导致无限嵌套的递归。这是因为每次减去运行它都会尝试自行运行。但这正是我试图通过首先分配减去= -
来阻止的?
如何避免这种无休止的递归?
答案 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 - 1
,x + 1
,x / 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"