tchakravarty
tchakravarty

Reputation: 10954

R: Why does eval evaluate in parent.frame() by default?

I was trying to evaluate some expressions in a function using eval but it would run into an error trying to find the objects which were defined in the function scope.

I realized that this was because eval's default environment is parent.frame(). Is there a good reason for this? I would expect it to be the same as, say, assign, that is, the current environment.

Here is an example (per Gabor's request):

fnFoo = function() {
    # assign 10 variables
    for(i in 1:10) assign(paste('v', i, sep = ''), rnorm(10))

    # find the variables by name and evaluate them
    Map(sum, lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)), eval))
}

# test that eval is unable to find a variable  declared in the function scope
fnFoo()

However, changing the function to

fnFoo = function() {
    # assign 10 variables
    for(i in 1:10) assign(paste('v', i, sep = ''), rnorm(10))

    # find the variables by name and evaluate them
    # Map(sum, lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)), eval))
    Map(sum, lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)), function(x) eval(x, envir = environment())))
}

# now it works
fnFoo()

works.

Thanks.

Upvotes: 0

Views: 681

Answers (1)

Robert Krzyzanowski
Robert Krzyzanowski

Reputation: 9344

Your problem is that you are being too clever with your lapply in conjuction with eval. Let's expand what is happening.

lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)), eval)

is equivalent to

lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)),
   function(x) eval(x))

However, a separate scope gets created for function(x) eval(x), which no longer has v1, v2, etc. in its immediate environment. Thus, you want to tell eval in conjunction with lapply to use the correct environment:

lapply(parse(text = grep('v', ls(envir = environment()), value = TRUE)),
       eval, envir = environment())

By the way, another approach is

apply(sapply(grep('v', ls(envir = environment()), value = TRUE), get, envir = environment()), 1, sum)

Upvotes: 1

Related Questions