如何让R函数自动获取正确环境以传递未求值表达式至substitute+eval组合
实现无需传递env参数的类subset函数
我想要实现类似subset()的功能,能够传递一个需要针对数据框求值的表达式,并且可以在其他函数内部调用该逻辑——这意味着要保留表达式,直到类subset函数被调用时再求值。
目前的实现通过传递默认值为sys.frame(sys.nframe())的env参数满足了需求,但缺点是所有外层函数都必须添加该参数才能维持嵌套特性,一旦外层函数省略env参数(比如示例中的f4),调用就会失败:
f1 = function(x, expr, env=sys.frame(sys.nframe())){ expr = substitute(expr, env) eval(expr, x) } f2 = function(x, expr, env=sys.frame(sys.nframe())){ f1(x, expr, env) } f3 = function(x, expr, env=sys.frame(sys.nframe())){ f2(x, expr, env) } f4 = function(x, expr){ f2(x, expr) # 未传递env参数 } m = head(mtcars, 2) # 简化输入 f1(m, mpg > 20) # 返回TRUE TRUE -- 符合预期 f2(m, mpg > 20) # 返回TRUE TRUE -- 成功 f3(m, mpg > 20) # 返回TRUE TRUE -- 成功 f4(m, mpg > 20) # 返回expr -- 失败 :(
能否改写f1,使其自动遍历调用栈并找到用于替换传入表达式的正确环境?
可以改写f1,让它自动向上遍历调用环境,找到表达式最初被传入的上下文,无需依赖外层函数传递env参数:
f1 = function(x, expr) { # 向上遍历父环境,找到表达式原始传入的环境 current_env <- parent.frame() # 循环判断:当前环境中的expr是否为符号(即从上层传递来的参数名) while (exists("expr", envir = current_env, inherits = FALSE) && is.symbol(get("expr", envir = current_env))) { current_env <- parent.env(current_env) } # 在正确的环境下替换表达式 expr_sub <- substitute(expr, current_env) # 在数据框环境中求值 eval(expr_sub, x) } # 外层函数无需再定义env参数 f2 = function(x, expr) { f1(x, expr) } f3 = function(x, expr) { f2(x, expr) } f4 = function(x, expr) { f2(x, expr) } # 测试 m = head(mtcars, 2) f1(m, mpg > 20) # [1] TRUE TRUE f2(m, mpg > 20) # [1] TRUE TRUE f3(m, mpg > 20) # [1] TRUE TRUE f4(m, mpg > 20) # [1] TRUE TRUE
原理说明
- 代码通过
parent.frame()获取当前函数的父环境,然后循环向上遍历:只要当前环境中的expr是一个符号(也就是从上层函数传递过来的参数名,而非用户输入的原始表达式),就继续往上找。 - 找到第一个包含原始表达式的环境后,用
substitute(expr, current_env)把表达式替换成用户输入的原始形式,最后在数据框x的环境中求值,就实现了和subset()类似的逻辑。
内容的提问来源于stack exchange,提问作者Colombo
相关产品推荐
相关产品推荐

