【问题标题】:changing parent environment of closure in R (a good idea)?改变 R 中关闭的父环境(一个好主意)?
【发布时间】:2014-03-29 23:30:42
【问题描述】:

我没有看到太多关于函数环境操作/在 R 中使用<<-adv-r 除外)的(流行)文献。特别是关于这些事情,R的禁忌是什么。为了使这个问题成为一个具体的问题,请考虑以下函数:

appendOne <- function(env=parent.frame()) {
   tmp <- function(.x) {
     eval(substitute(.x <<- c(.x, "1")))
   }
   parent.env(environment(tmp)) <- env
   return(tmp)
}

g <- function() {
   .y <- 4
   appendOne()(.y)
   .y 
}

appendOne 的意义非常明显。现在的问题是(我知道这部分是主观的):

  1. 在 R 中,这种仅出于副作用而创建函数的策略是危险的吗?
  2. 这种编程模式在R中是“禁忌”吗?除了最高级别之外,我看不到太多eval-substitute 模式。这是因为它很难向初学者解释,还是因为它不被鼓励?

【问题讨论】:

  • 对没有副作用的函数的偏好是functional programming 的标志。正如链接的维基百科页面的第一段所解释的那样,“消除副作用,即不依赖于函数输入的状态变化,可以更容易理解和预测程序的行为,这是关键之一开发函数式编程的动机。”
  • 另外,FWIW,对g()(或就此而言对appendOne())的函数调用会冻结我的 R 会话。
  • 他试图在定义之前从appendOne 内部访问g。这将导致奇怪的行为。
  • 糟糕!那是一个错字……已更正。

标签: r functional-programming


【解决方案1】:

函数式编程大力鼓励构建副作用最小的函数。这样做的原因是,如果一个函数的副作用为零,则可以提供其行为完整性的完整证明——它不会修改其本地环境之外的任何内容。

但是,使用eval(substitute(...)) 模式“进入”调用环境可能有充分的理由——即,出于优化目的和显着改善体验的非标准评估用户的。

例如,在我的一个包中,我perform a very complicated evaluation in the calling environment,非常小心不要定义任何附带的局部变量,因为我非常关心优化并且不想下降到 C。

例如,如果您将数据框传递给函数,对该数据框的一列进行修改,然后将其返回,R 将复制整个数据框。您可以将其包装在仅包含该数据框的环境中,但这也会使事情变得更难理解。如果您知道用户知道底层函数的副作用,则使用非标准评估可以提高性能:

(function(df) eval.parent(substitute(df[[1]] &lt;- 2 * df[[1]])))(iris)

【讨论】:

    猜你喜欢
    • 2015-02-03
    • 1970-01-01
    • 2014-11-04
    • 2011-02-07
    • 2015-12-10
    • 2019-05-18
    • 2012-12-15
    • 2013-01-02
    • 2010-11-27
    相关资源
    最近更新 更多