为何函数名与参数名相同时,默认参数调用函数会报错?
函数名与参数名同名时默认参数调用失败的底层原因解析
当函数的参数名和外部函数名同名,且将该外部函数调用作为参数默认值时,会触发递归求值错误,先看报错的示例代码:
f1 <- function(){ 2 } f2 <- function(f1 = f1()){ f1 * 2 } f2() #> Error in f2(): promise already under evaluation: recursive default argument reference or earlier problems?
底层逻辑:R的Promise机制与作用域查找
R处理函数参数默认值时,会用到**Promise(延迟求值)**机制:参数不会在函数定义阶段立即计算,而是等到函数内部第一次调用该参数时才触发求值。
当执行f2()时,参数f1的默认值开始求值,过程如下:
- 要计算
f1(),R会按作用域查找顺序寻找f1对象:先在f2的局部环境里查找,再去父环境(比如全局环境)查找。 - 此时
f2的局部环境中已经存在一个名为f1的Promise对象(就是当前正在求值的参数),R会优先匹配这个Promise,而非全局环境里的f1函数。 - 但这个Promise本身正处于求值过程中,尝试调用它就会触发"promise already under evaluation"的递归引用错误。
修复方案的生效原理
修复方案1:重命名外部函数
f <- function(){ 2 } f2 <- function(f1 = f()){ f1 * 2 } f2() #> [1] 4
把全局环境的函数从f1改名为f后,计算默认值f()时,R在f2的局部环境里找不到f,就会去全局环境定位到f函数,正常执行调用,不会和参数f1产生冲突。
修复方案2:重命名函数参数
f1 <- function(){ 2 } f2 <- function(.f1 = f1()){ .f1 * 2 } f2() #> [1] 4
把f2的参数名改为.f1后,计算默认值f1()时,R在f2的局部环境里找不到名为f1的对象,就会去全局环境找到f1函数,顺利完成调用,参数.f1接收返回值2后即可正常计算。
内容的提问来源于stack exchange,提问作者Austin Graves
相关产品推荐
相关产品推荐

