2013-03-26 12 views
4

我在循环中定义函数并试图强制评估循环变量而不必携带私有环境。R范围:在没有本地环境的情况下在函数中强制变量替换

实施例:一组函数handlers$h1handlers$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,...

相反,所有的函数返回6i当前值。

为了解决这个问题,我可以用一个封闭的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并将其直接替换为defin ition,消除对环境的需求?

我能想到的唯一办法是:

  • 使用eval(东西我不喜欢这样做);
  • 写出每个定义由手与1-6直接取代的(在这种情况下,其中只有6个功能正常,但在一般的不可伸缩)
+0

R中的每个功能都有一个相关的环境:你为什么担心呢? – hadley 2013-03-26 13:23:28

+0

另外,你没有通过使用闭包来解决它(你已经这样做了),你可以通过使用'force'来解决它。 – hadley 2013-03-26 13:31:34

回答

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) 

substitute

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

不错!就像第二个一样。干杯! – 2013-03-26 03:43:11

+0

我不会那么担心不使用'body' - 哎呀,Mathematica的一半都是关于修改函数中的对象的:-) – 2013-03-26 11:47:00

+0

-1当你不需要时提及解析 – hadley 2013-03-26 13:27:24

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手动修改引用调用。

另一个很酷的(!IMO)在pryr功能unenclose,其通过在封闭的环境中定义的变量替换unencloses功能:

msg <- function(i) { 
    force(i) 
    function() message(i) 
} 
msg(1) 
# function() message(i) 
# <environment: 0x102dc6ca0> 
unenclose(msg(1)) 
# function() 
# message(1) 

但他们真的是没有缺点使用原始封闭。

1

这里有两种方法。他们是相同的,除了在每个##行:

甲醛< -

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 
} 
相关问题