如何让用户自定义函数绑定并调用目标函数内部环境的P函数?
问题分析
你遇到的核心问题是函数作用域的查找顺序:user_fun在全局环境定义,它的闭包环境绑定到全局环境。当my_fun里用eval执行user_fun(0.4, C)时,user_fun内部查找P函数时,会先检查自身执行环境,再去闭包环境(全局)找,不会去你创建的环境e,所以报"找不到函数P"的错误。
解决方案
我们可以复制用户定义的user_fun,临时修改其闭包环境为my_fun内部的环境e,再执行这个修改后的函数副本(不会影响全局的原函数)。修改后的my_fun代码如下:
library(rlang) my_fun <- function(boolex, probs){ e <- env(caller_env(), .probs = probs, P = function(i){ .probs[as.character(enexpr(i))] } ) # 提取传入的函数调用表达式 boolex_call <- enexpr(boolex) # 获取用户定义的函数名 fun_name <- call_name(boolex_call) # 从调用环境中取出原函数 original_fun <- get(fun_name, envir = caller_env()) # 复制函数并修改其闭包环境为e modified_fun <- original_fun fn_env(modified_fun) <- e # 替换调用表达式中的函数为修改后的副本 boolex_call[[1]] <- modified_fun # 执行修改后的调用 eval(boolex_call, e) } user_fun <- function(x, y){ x >= P(y) } # 测试运行 my_fun( user_fun(0.4, C), c(A=0.1, B=0.2, C=0.3, D=0.4) )
运行这段代码会返回TRUE,符合预期(0.4 >= 0.3)。
为什么之前的尝试失败?
你之前直接修改全局user_fun的闭包环境:
fn_env(get(call_name(enexpr(boolex)))) <- current_env()
这种做法会永久修改全局的user_fun,不仅有副作用,而且当my_fun执行完毕后,current_env()(即my_fun的执行环境)会被回收,后续调用user_fun会出现错误。而我们的方案是复制函数,只修改临时副本的环境,执行完就丢弃,不会影响全局状态。
另一种简化思路(可选)
如果允许用户在user_fun里稍微调整写法,可以不用修改函数环境,而是让P从调用环境中查找:
user_fun <- function(x, y){ x >= get("P", parent.frame())(y) }
但这种写法不够直观,不如修改函数闭包环境的方案友好。
内容的提问来源于stack exchange,提问作者Clark
相关产品推荐
相关产品推荐

