本文介绍了R 范围:在没有本地环境的函数中强制变量替换的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在循环中定义函数并尝试强制对循环变量求值,而不必携带私有环境.

I'm defining functions in a loop and trying to force evaluation of a loop variable without having to carry around a private environment.

示例:一组函数 handlers$h1, handlers$h2, ..., handlers$h6 只是通过1, 2, ..., 6 到另一个像这样的函数:

Example: a set of functions handlers$h1, handlers$h2, ..., handlers$h6 that just pass through the 1, 2, ..., 6 to another function like so:

handlers <- list()
for (i in 1:6) {
    handlers[[paste0('h', i)]] <- function () {
        message(i) # <-- example
    }
}

所以 handlers$h1() 应该是消息 1,handlers$h2() 应该是消息 2,...

So handlers$h1() should message 1, handlers$h2() should message 2, ...

相反,所有函数都返回6,即i当前值.

Instead, all of the functions return 6, the current value of i.

为了解决这个问题,我可以使用 在这个问题中指定的闭包

To get around this I can use a closure as specified in this question

msg <- function(i) {
    force(i)
    function () { message(i) }
}

for (i in 1:6) {
    handlers[[paste0('h', i)]] <- msg(i)
}

现在每个函数都按预期工作,但是每个函数都必须携带自己的环境:

Now each function works as expected, but each function has to carry around its own environment:

handlers$h1
# function () { message(i) }
# <environment: 0x9342b80>

如何才能使 handlers$h1 打印 function () { message(1) },即评估 i 并将其直接替换到定义中,从而消除对环境的需求?

How can I make it so that handlers$h1 prints function () { message(1) }, i.e. evaluates the i and substitutes it directly into the definition, removing the need for the environment?

我能想到的唯一方法是:

The only ways I can think of are to:

  • 使用 eval(我不喜欢这样做);
  • 手工写出每个定义,直接替换 1-6(在这种情况下,只有 6 个函数,但通常不可扩展)

推荐答案

以下是一些使用 body

你可以使用 bquote

handlers <- list()

for (i in 1:6) {
  handlers[[paste0('h', i)]] <- function () {}
  body( handlers[[paste0('h', i)]]) <- bquote(message(.(i)))
}

handlers$h1
## function () 
##   message(1L)

替换

for (i in 1:6) {
  handlers[[paste0('h', i)]] <- function () {}
  body( handlers[[paste0('h', i)]]) <- substitute(message(i), list(i=i))
}

这篇关于R 范围:在没有本地环境的函数中强制变量替换的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 03:57