考虑以下函数,如果条件为Position
,它将用值替换lhs
TRUE
如果`==<-` <- function (e1, e2, value) replace(e1, e1 == e2, value)
将x替换为42:
x == 3
到目前为止很好,但是如果x <- 3
x == 3 <- 42
x
# [1] 42
有副作用怎么办?到目前为止,即使我的病情是value
,它也会被评估。
FALSE
有没有解决的办法?
请参阅以下有关此问题的解决方法,但是我想看看是否还有更多解决方法。
编辑:
这解决了sotos的评论:
# desired: if x == 100, stop
x == 100 <- stop("equals 100!")
# Error: equals 100!
答案 0 :(得分:2)
以下是解决此问题的几种方法:
quote
并修改==<-
,以便它始终评估引用的呼叫~
作为引用函数~
作为函数的简写,并使用rlang::as_function
delay
引用输入并添加类delayed
,以便仅对未引用的输入和delayed
引用的输入进行评估。<-
来识别==<-
,并始终delay
lhs 最后一种方法是唯一一种无需更改接口即可使用的方法,尽管它的工作原理是覆盖<-
,这通常是不建议的。
quote
并修改==<-
,以便它始终评估引用的呼叫如果我们知道我们不想分配未评估的通话 我们可以确保我们的函数评估所有内容,然后引用 输入。
`==<-` <- function (e1, e2, value) {
cond <- e1 == e2
if(any(cond))
replace(e1, e1 == e2, eval.parent(value))
else e1
}
x <- 42
x == 100 <- quote(stop("equals 100!"))
x <- 100
x == 100 <- quote(stop("equals 100!"))
# Error in eval(expr, envir, enclos) : equals 100!
~
作为报价功能如果我们知道我们不想分配公式
我们可以使用~
代替引号。
`==<-` <- function (e1, e2, value) {
cond <- e1 == e2
if(any(cond))
replace(e1, e1 == e2,
if(inherits(value, "formula"))
eval.parent(as.list(value)[[2]])
else
value)
else e1
}
x <- 42
x == 100 <- ~stop("equals 100!")
x <- 100
x == 100 <- ~stop("equals 100!")
# Error in eval(expr, envir, enclos) : equals 100!
~
作为函数的简写,并使用rlang::as_function
如果我们不想分配函数或公式,则可以更进一步,并从中构建功能。
`==<-` <- function (e1, e2, value) {
cond <- e1 == e2
if(any(cond))
replace(e1, e1 == e2,
if(inherits(value, "formula") || is.function(value))
rlang::as_function(value)(e1)
else
value)
else e1
}
x <- 42
x == 100 <- ~stop("equals 100!")
x <- 100
x == 100 <- ~stop("equals 100!")
# Error in eval(expr, envir, enclos) : equals 100!
x == 100 <- sqrt
x
# [1] 10
delay
引用输入并添加类delayed
我们可以创建一个函数delay
,该函数将quote
的{{1}}表达式,并添加一个类value
,我们的函数将其识别到"delayed"
处的调用中合适的时机:
trigger
优点是它可以与可能触发错误的任何代码一起工作,缺点是`==<-` <- function (e1, e2, value) {
cond <- e1 == e2
if(any(cond))
replace(e1, e1 == e2,
if (inherits(x,"delayed")) eval.parent(x) else x)
else e1
}
delay <- function(x) {
x <- substitute(x)
class(x) <- "delayed"
x
}
x <- 42
x == 100 <- delay(stop("equals 100!"))
x <- 100
x == 100 <- delay(stop("equals 100!"))
# Error in eval(expr, envir, enclos) : equals 100!
是一个奇怪的函数,仅在特定上下文中才有意义。
我们可以通过参考包装帮助定义适当的打印方法来减轻尴尬:
delay
我们可以使用相同的原理设计一个print.delayed <- function(x,...){
message(
"Delayed call, useful as a `value` argument of `mmassign` assignment functions.\n",
"See ?mmassign::delay.")
print(unclass(x),...)
x
}
delay(stop("equals 100!"))
# delayed call, useful as a `value` argument of `mmassign` assignment functions.
# See ?mmassign::delay.
# stop("equals 100!")
函数,该函数的行为将“延迟”
STOP
STOP <- function(...) `class<-`(substitute(stop(...)), "delayed")
x <- 42
x == 100 <- STOP("equals 100!")
x <- 100
x == 100 <- STOP("equals 100!")
# Error in eval(expr, envir, enclos) : equals 100!
STOP("equals 100!")
# delayed call, useful as a `value` argument of `mmassign` assignment functions.
# See ?mmassign::delay.
# stop("equals 100!")
以识别<-
,并且总是==<-
lhs 如果我们重写delay
可以使它起作用,但这当然不是一个好习惯,所以只是为了好玩。如果LHS的第一个元素是<-
,则引用值并添加类==
并按上述步骤进行。
"delayed"