当eval'ing时,match.call在错误的环境中调用

Kon*_*lph 9 eval r substitution

我尝试let使用以下语义实现一个函数:

> let(x = 1, y = 2, x + y)
[1] 3
Run Code Online (Sandbox Code Playgroud)

...在概念上有点类似于substitute语法with.

以下代码几乎可以工作(例如上面的调用工作):

let <- function (...) {
    args <- match.call(expand.dots = FALSE)$`...`
    expr <- args[[length(args)]]
    eval(expr,
         list2env(lapply(args[-length(args)], eval), parent = parent.frame()))
}
Run Code Online (Sandbox Code Playgroud)

注意嵌套eval,外部用于评估实际表达式,而inner用于评估参数.

不幸的是,后一种评估发生在错误的背景下.当尝试let使用检查当前帧的函数调用时,这变得很明显,例如match.call:

> (function () let(x = match.call(), x))()
Error in match.call() :
  unable to find a closure from within which 'match.call' was called
Run Code Online (Sandbox Code Playgroud)

我想过提供父框架作为评估环境eval,但这不起作用:

let <- function (...) {
    args <- match.call(expand.dots = FALSE)$`...`
    expr <- args[[length(args)]]
    parent <- parent.frame()
    eval(expr,
         list2env(lapply(args[-length(args)], function(x) eval(x, parent)),
                  parent = parent)
}
Run Code Online (Sandbox Code Playgroud)

这会产生相同的错误.这引出了我的问题:如何match.call评估?为什么这不起作用?而且,我该如何使这项工作?

flo*_*del 6

这个重写会解决你的问题吗?

let <- function (expr, ...) {
    expr  <- match.call(expand.dots = FALSE)$expr
    given <- list(...)
    eval(expr, list2env(given, parent = parent.frame()))
}

let(x = 1, y = 2, x + y)
# [1] 3
Run Code Online (Sandbox Code Playgroud)

  • @KonradRudolph - 这只是一个结果或[R的规则/算法匹配参数](http://stat.ethz.ch/R-manual/R-devel/doc/manual/R-lang.html#Argument-matching ).首先处理命名的参数(这里是`x = 1`和`y = 2`),它们都没有与名为formal(`expr`)的名称相匹配的名称.然后,正如上面的链接所提到的那样"任何不匹配的形式参数都按顺序绑定到未命名的提供参数." 在这里,这意味着`x + y`被绑定到`expr`. (2认同)
  • 在`.expr`中使用`.`前缀是一种非常常见的方法,可以避免这种情况并保留有意义的变量名. (2认同)
  • @KonradRudolph - 更糟糕的是,该链表上的第二条规则意味着任何名为`e`或`ex`或`exp`的参数都将与`expr`匹配.部分参数匹配是恕我直言,这是一个糟糕的设计决定,现在由许多使用它的贡献函数+/-锁定. (2认同)