R 什么&x2019;嵌套的“eval”的环境和外壳是什么? 背景

R 什么&x2019;嵌套的“eval”的环境和外壳是什么? 背景,r,eval,environment,R,Eval,Environment,我正在为lambdas创建一个快捷方式,因为反复使用函数(…)…会使我的代码非常混乱。作为补救措施,我正在尝试从其他语言(如Haskell)中获得灵感的替代语法,尽可能在R中实现。简化后,我的代码如下所示: f <- function (...) { args <- match.call(expand.dots = FALSE)$... last <- length(args) params <- c(args[-last], names(args

我正在为lambdas创建一个快捷方式,因为反复使用
函数(…)…
会使我的代码非常混乱。作为补救措施,我正在尝试从其他语言(如Haskell)中获得灵感的替代语法,尽可能在R中实现。简化后,我的代码如下所示:

f <- function (...) {
    args <- match.call(expand.dots = FALSE)$...
    last <- length(args)
    params <- c(args[-last], names(args)[[last]])

    function (...)
        eval(args[[length(args)]],
             envir = setNames(list(...), params),
             enclos = parent.frame())
}
等等

当然,真正的目的是将其用于高阶函数1:

问题 不幸的是,我有时不得不嵌套高阶函数,然后它就停止工作了:

f(x = Map(f(y = x + y), 1:2))(10)
产生“在
eval(expr、envir、enclose)中出错”
:对象
x
未找到”。使用
函数
而不是
f
的概念等效代码可以工作。此外,其他嵌套场景也可以工作:

f(x = f(y = x + y)(2))(3) # => 5
我怀疑罪魁祸首是地图内部嵌套的
f
的父环境:它是顶层环境,而不是外部
f
。但我不知道如何解决这个问题,这也让我对上述第二种情况是否有效感到困惑。相关问题()建议了一些不适用于我的情况的变通方法

很明显,我对R中环境的理解存在差距。我想要的可能吗



1当然,这个例子可以简单地写成
(1:10)*2
。真正的应用程序具有更复杂的对象/操作。

答案是将
parent.frame()
附加到输出函数的环境:

f <- function (...) {
    args <- match.call(expand.dots = FALSE)$...
    last <- length(args)
    params <- c(args[-last], names(args)[[last]])

    e <- parent.frame()

    function (...)
        eval(args[[length(args)]],
             envir = setNames(list(...), params),
             enclos = e)
}
f好问题

为什么你的代码失败 您的代码失败,因为
eval()提供的
enclose=
参数没有指向调用堆栈上足够远的位置,无法到达您希望它下次搜索未解析符号的环境

下面是调用堆栈的局部图,从该调用堆栈的底部可以调用
parent.frame()
。(要理解这一点,重要的是要记住,调用父.frame()
的函数调用不是
f()
,而是调用由
f()
返回的匿名函数(我们称之为
fval


你能让你的函数只使用输入变量吗?例如,
f(x=Map(f(x,y=x+y),x,1:2))(10)
@flodel问题是:你的变通方法为什么有效?那
x
也不是全球性的,是吗?它是从外部
f
中传递给
Map
的参数的一部分。当然,我希望能够避免这种客户端解决方案,并准确地复制
函数
s的工作方式。您不使用“lambda.r”包有什么原因吗?(我怀疑你遇到困难的原因是R中的函数携带着它们的构造环境……所谓的词法作用域而不是动态作用域。)@DWin是的,
lambda.R
并没有达到我想要的效果。特别是,它的语法虽然本身非常有趣,但不够简洁,无法将它与默认的
函数
区别开来。它只短了三个字符,并且声明了一个命名函数(不管包名如何)?我认为它是有效的,因为它显式地覆盖了在函数定义时建立的评估环境。它并不是真的附加了一个新的框架,而是建立了一种机制,在调用函数时替换原来的框架。嗯,我必须再考虑一下这个问题。@DWin——也许和你说的一样,关键似乎是flodel的代码在定义函数时修复了封闭的环境,而不是等到以后进行功能评估时再进行。(这里我当然指的是
f()
返回的函数的定义和计算)。有关更多详细信息,包括解释为什么他的答案中的
parent.frame(n=1)
指向调用堆栈上的相应计算框架,请参见我刚才添加的答案。
f(x = f(y = x + y)(2))(3) # => 5
f <- function (...) {
    args <- match.call(expand.dots = FALSE)$...
    last <- length(args)
    params <- c(args[-last], names(args)[[last]])

    e <- parent.frame()

    function (...)
        eval(args[[length(args)]],
             envir = setNames(list(...), params),
             enclos = e)
}
## Note: E.F. = "Evaluation Frame"
##       fval = anonymous function returned as value of nested call to f()

f(   <-------------------------  ## E.F. you want, ptd to by parent.frame(n=3)      
  Map(
      mapply(   <--------------------  ## E.F. pointed to by parent.frame(n=1)
             fval(                  |
                  parent.frame(n=1  |
f(   <--------------------- ## Evaluation frame of the nested call to f()
  Map(f(                  |
        parent.frame(n=1  |