9

I am trying to run a chunk of R code in a sandbox-ed fashion, by loading all the necessary dependencies (functions and data) into a new environment and evaluating an expression within that environment. However, I'm running into trouble with functions calling other functions in the environment. Here's a simple example:

jobenv <- new.env(parent=globalenv())
assign("f1", function(x) x*2, envir=jobenv)
assign("f2", function(y) f1(y) + 1, envir=jobenv)
expr <- quote(f2(3))

Using eval on expr fails since f2 can't find f1

> eval(expr, envir=jobenv)
Error in f2(3) : could not find function "f1"

whereas explicitly attaching the environment works

> attach(jobenv)
> eval(expr)
[1] 7

I'm probably missing something obvious, but I couldn't find any permutation of the eval call that works. Is there a way to get the same effect without attaching the environment?

4

2 回答 2

8

There are a number of ways of doing this, but I kind of like this one:

jobenv <- new.env(parent=globalenv())

local({
    f1 <- function(x) x*2
    f2 <- function(y) f1(y) + 1
}, envir=jobenv)

## Check that it works
ls(jobenv)
# [1] "f1" "f2"
local(f2(3), envir=jobenv)
# [1] 7
eval(quote(f2(3)), envir=jobenv)
# [1] 7
于 2013-07-18T20:11:05.587 回答
6

范围是在创建函数时定义的,而不是在调用它时定义的。请参阅R手册简介的第 10.7 节。

这对我来说似乎有点奇怪,但即使你避免assign一起使用,你也会得到相同的行为$<-

jobenv <- new.env(parent=globalenv())
jobenv$f1 <- function(x) x*2
jobenv$f2 <- function(y) f1(y) + 1
expr <- quote(f2(3))
eval(expr, envir=jobenv)

这似乎是因为f1and的封闭环境f2是全局环境。我本来希望它是jobenv

> environment(jobenv$f1)
<environment: R_GlobalEnv>
> environment(jobenv$f2)
<environment: R_GlobalEnv>

一种解决方案是显式设置每个函数的环境......但必须有一种更简单的方法。

> environment(jobenv$f1) <- jobenv
> environment(jobenv$f2) <- jobenv
> eval(expr, envir=jobenv)
[1] 7
于 2013-07-18T19:35:07.447 回答