In my apparent naievety, I assumed that when one calls eval
and specifies an environment (envir
), the expression (expr
) is evaluated in that environment.
However :-)
This works as expected:
xx <- 10
nn <- 20
exprs <- binom.test(x=xx,n=nn)
eval(exprs);
By default, eval
evaluates in parent.frame()
, which the help reveals is [t]he parent frame of a function evaluation is the environment in which the function was called.
So in the above example, this is the global environment, where indeed, xx
and nn
are defined. So far, so good.
newEnv <- new.env();
assign('xxx', 10, envir = newEnv);
assign('nnn', 30, envir = newEnv);
exprs2 <- expression(binom.test(x=xxx,n=nnn));
eval(exprs2, envir=newEnv);
This also works as expected; xxx
and nnn
are defined in the newEnv
environment, and binom.test
is evaluated in that environment.
Now we wrap this in a function (the one I'm trying to build - I'm building it using the pwr
package, but for this example I'm using binom.test
because it's base R and it still doesn't work :-)
loopFunction <- function(expr,
...) {
### Get all 'dots' in a named list
arguments <- list(...);
argNames <- names(arguments);
if (any(length(tail(arguments, -2) > 1))) {
stop("Only the first two arguments may have length > 1!");
}
for (esIndex in seq_along(arguments[[1]])) {
for (pwrIndex in seq_along(arguments[[2]])) {
tempEnvironment <-
new.env();
assign(argNames[1], arguments[[1]][esIndex],
envir = tempEnvironment);
assign(argNames[2], arguments[[2]][pwrIndex],
envir = tempEnvironment);
if (length(arguments) > 2) {
for (i in 3:length(arguments)) {
assign(argNames[i], arguments[[i]],
envir = tempEnvironment);
}
}
print(argNames);
print(as.list(tempEnvironment));
print(ls(tempEnvironment));
print(get('x', envir=tempEnvironment));
print(get('n', envir=tempEnvironment));
return(eval(expr = expression(expr),
envir = tempEnvironment)$estimate);
}
}
}
When running this, you get:
loopFunction(binom.test(x=x,n=n), x=c(10,20), n=c(30, 100));
#> [1] "x" "n"
#> $x
#> [1] 10
#>
#> $n
#> [1] 30
#>
#> [1] "n" "x"
#> [1] 10
#> [1] 30
#> Error in binom.test(x = x, n = n): object 'x' not found
So, that error stumps me. clearly, x
and n
exist in tempEnvironment
; and tempEnvironment
is passed to eval
.
Why does this suddenly no longer work? Does this work differently inside functions? Am I missing something obvious?
I am not sure why expression()
doesn't work in this context. However, it works if you write expr
as a string and replace expression(expr)
by parse(text=expr)
:
loopFunction <- function(expr,
...) {
### Get all 'dots' in a named list
arguments <- list(...);
argNames <- names(arguments);
if (any(length(tail(arguments, -2) > 1))) {
stop("Only the first two arguments may have length > 1!");
}
for (esIndex in seq_along(arguments[[1]])) {
for (pwrIndex in seq_along(arguments[[2]])) {
tempEnvironment <-
new.env();
assign(argNames[1], arguments[[1]][esIndex],
envir = tempEnvironment);
assign(argNames[2], arguments[[2]][pwrIndex],
envir = tempEnvironment);
if (length(arguments) > 2) {
for (i in 3:length(arguments)) {
assign(argNames[i], arguments[[i]],
envir = tempEnvironment);
}
}
print(argNames);
print(as.list(tempEnvironment));
print(ls(tempEnvironment));
print(get('x', envir=tempEnvironment));
print(get('n', envir=tempEnvironment));
return(eval(expr=parse(text=expr), envir =tempEnvironment)$estimate)
}
}
}
loopFunction("binom.test(x, n)", x=10, n=30)
Result:
> loopFunction("binom.test(x, n)", x=10, n=30)
[1] "x" "n"
$`x`
[1] 10
$n
[1] 30
[1] "n" "x"
[1] 10
[1] 30
probability of success
0.3333333