我在循环中定义函数并尝试强制评估循环变量,而不必携带私有环境。
示例:一组函数handlers$h1
,handlers$h2
,...,handlers$h6
只需将1,2,...,6传递给另一个函数,如下所示:
handlers <- list()
for (i in 1:6) {
handlers[[paste0('h', i)]] <- function () {
message(i) # <-- example
}
}
所以handlers$h1()
应该留言1,handlers$h2()
留言2,......
相反,所有函数都返回6
,i
的当前值。
为了解决这个问题,我可以使用一个闭包specified in this question
msg <- function(i) {
force(i)
function () { message(i) }
}
for (i in 1:6) {
handlers[[paste0('h', i)]] <- msg(i)
}
现在每个函数都按预期工作,但每个函数都必须随身携带:
handlers$h1
# function () { message(i) }
# <environment: 0x9342b80>
如何使handlers$h1
打印function () { message(1) }
,即评估i
并将其直接替换为定义,从而消除对环境的需求?
我能想到的唯一方法是:
eval
(我不想做的事); 答案 0 :(得分:7)
以下是一些使用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)
或substitute
for (i in 1:6) {
handlers[[paste0('h', i)]] <- function () {}
body( handlers[[paste0('h', i)]]) <- substitute(message(i), list(i=i))
}
答案 1 :(得分:3)
不幸的是,基地R缺乏手工制作功能的功能,但pryr供应make_function
:
library(pryr)
handlers <- list()
for (i in 1:6) {
body <- substitute(message(i), list(i = i))
f <- make_function(alist(), body)
handlers[[paste0('h', i)]] <- f
}
请注意使用substitute
手动修改引用的电话。
pryr中的另一个很酷的(IMO!)函数是unenclose
,它通过替换封闭环境中定义的变量来取消函数:
msg <- function(i) {
force(i)
function () message(i)
}
msg(1)
# function () message(i)
# <environment: 0x102dc6ca0>
unenclose(msg(1))
# function ()
# message(1)
但是使用原始封口确实没有任何缺点。
答案 2 :(得分:1)
这有两种方法。它们是相同的,除了每个中的##行:
<强>缩甲醛&LT; - 强>
handlers <- list()
f <- function() message(i)
for (i in 1:6) {
formals(f) <- list(i = i) ##
handlers[[paste0('h', i)]] <- f
}
<强>微量强>
handlers <- list()
f <- function() message(i)
for (i in 1:6) {
trace(f, bquote(i <- .(i)), print = FALSE) ##
handlers[[paste0('h', i)]] <- f
}