替换函数(例如names<-
)在像 那样调用时似乎不使用惰性求值names(x) <- c("a", "b")
。
为了演示,让我们定义一个函数来获取数字的小数部分和相应的替换函数 - 但在替换函数内部,包含一行来打印解除约束的value
参数。
fractional <- function(x) {
x %% 1
}
`fractional<-` <- function(x, value) {
print(rlang::enexpr(value))
invisible(x %/% 1 + value)
}
现在如果我们fractional<-
直接调用,它会打印我们给出的表达式value
:
x <- 10.1
`fractional<-`(x, 0.2 + 0.2)
#> 0.2 + 0.2
但是如果我们以赋值形式调用它,它会打印表达式的求值结果:
x <- 10.1
fractional(x) <- 0.2 + 0.2
#> [1] 0.4
语言定义解释了替换函数,例如:
names(x) <- c("a","b")
相当于
`*tmp*` <- x x <- "names<-"(`*tmp*`, value=c("a","b")) rm(`*tmp*`)
但这并不能重现这种行为:
x <- 10.1
`*tmp*` <- x
x <- "fractional<-"(`*tmp*`, value=0.2 + 0.2)
rm(`*tmp*`)
#> 0.2 + 0.2
其中内部发生了什么事情<-
使得它在value
评估后被传递,有什么方法可以规避这种行为?fractional<-
编辑: @SamR 指出使用substitute
捕获了承诺中的表达式:
x <- 10.1
`fractional<-` <- function(x, value) {
print(substitute(value))
invisible(x %/% 1 + value)
}
fractional(x) <- 0.2 + 0.2
#> 0.2 + 0.2
因此,显然我错误地认为value
在传递给之前对进行了评估fractional<-
。但是,我仍然非常想知道为什么 base::substitute
在这里按预期工作,而 rlang::enexpr
和朋友却没有。毕竟,在内部enexpr
使用substitute
:
enexpr <- function(arg) {
.Call(ffi_enexpr, substitute(arg), parent.frame())
}
在 R Studio 中进行调试表明,无论是以赋值形式调用fractional(x) <- 0.2 + 0.2
还是以前缀形式调用时"fractional<-"(x, 0.2 + 0.2)
,fractional<-
都会传递一个未评估的承诺value
:
当以前缀形式调用时,它仍未被计算:
但是在以赋值形式调用时,会在调用之后进行评估enexpr
:
我想知道这是否与在赋值形式中该函数由原始函数调用有关<-
?但不清楚为什么会有所不同。