为何R语言替换函数在赋值形式下未按惰性求值运行?
R赋值式替换函数的惰性求值异常与解决办法
现象复现
先定义测试用的小数部分操作函数及对应替换函数:
fractional <- function(x) { x - floor(x) } `fractional<-` <- function(x, value) { print(substitute(value)) x - fractional(x) + value }
直接调用替换函数时,能正常捕获传入的原始表达式:
x <- 10.1 `fractional<-`(x, 0.2 + 0.2) #> 0.2 + 0.2
但使用R的赋值语法糖调用时,打印的却是表达式求值后的结果:
x <- 10.1 fractional(x) <- 0.2 + 0.2 #> [1] 0.4
原因分析
R官方文档指出,f(x) <- y这类赋值式替换等价于x <- f<-(x, y),但实际解析器对赋值语法糖的参数绑定有特殊逻辑:
- 赋值式调用时,右侧表达式会被包装为一个特殊的承诺对象传递给替换函数;
rlang::enexpr在处理这种特殊承诺对象时,会触发其求值(内部调用栈解析逻辑导致承诺兑现),因此无法捕获原始表达式;base::substitute直接在当前函数环境中捕获参数的表达式形式,不会触发承诺对象的求值,因此能正常获取原始表达式。
规避方法
方法1:使用base::substitute捕获表达式
直接用基础包的substitute函数捕获value的原始表达式,是最简洁的解决方案:
`fractional<-` <- function(x, value) { expr <- substitute(value) print(expr) x - fractional(x) + eval(expr) }
测试赋值式调用:
fractional(x) <- 0.2 + 0.2 #> 0.2 + 0.2
方法2:使用rlang的引用对象捕获
如果依赖rlang工具链,可以用enquo创建引用对象,再提取表达式,避免触发承诺求值:
library(rlang) `fractional<-` <- function(x, value) { expr <- quo_get_expr(enquo(value)) print(expr) x - fractional(x) + eval(expr) }
测试效果一致:
fractional(x) <- 0.2 + 0.2 #> 0.2 + 0.2
内容的提问来源于stack exchange,提问作者Eonema
相关产品推荐
相关产品推荐

