You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让用户自定义函数绑定并调用目标函数内部环境的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 14:20:24