[R] Understanding eval

Duncan Murdoch murdoch at stats.uwo.ca
Sun Dec 23 15:15:13 CET 2007


On 22/12/2007 5:45 PM, Charilaos Skiadas wrote:
> On Dec 22, 2007, at 4:44 PM, Duncan Murdoch wrote:
>>> 5) eval then creates the environment where this evaluation will  
>>> take  place. It does that by creating an environment containing  
>>> the frame  "a=5", and with enclosing environment the parent frame  
>>> of foo, which  is bar's environment.
>>> 6) So, as I understand it, the symbol "er" is going to now be   
>>> evaluated in an environment where a is set to 5 and er is set to  
>>> a,  along with whatever is in the user's workspace.
>> I think this part is wrong.  A better description is:
>>
>> er is going to be evaluated in an environment where a is set to 5.   
>> The parent of that environment is the bar evaluation frame, where  
>> er is set to be a promise to evaluate a in the global environment.
>>
>>> 7) So the first step now is looking up a definition for er.  
>>> Nothing  is found in the current frame, so the evaluation proceeds  
>>> to bar's  environment, where the association "er=a" is found, so  
>>> er is replaced  by a.
>> No, at this point an attempt is made to force the promise.   
>> Promises have their own associated environments, and that's where  
>> the evaluation takes place.  In the case of the er object, the  
>> associated environment is the one where bar(a) was called, i.e. the  
>> global environment.
>>
>>> 8) Now, and perhaps this is where I misunderstand things, the  
>>> lookup  for a will take place. My thinking was that the lookup  
>>> would start  from the evaluation environment that eval created,  
>>> and hence would  locate the a=5 value. But this is clearly not  
>>> what happens.
>>> Anyway, hope someone will correct me where I'm wrong, and explain  
>>> to  me what I am doing wrong, and ideally how to diagnose such  
>>> things.
>> Diagnosing things like this is hard.  Promises are very difficult  
>> things to look at:  as soon as you try to do anything with them  
>> they get evaluated, and there's no way in R code to display them  
>> without that.
>> You can use substitute() to extract the expression part, but  
>> there's no way to extract the environment part.  Maybe there should  
>> be, but it's tricky to get the semantics right.  If the function  
>> environment() worked to extract the environment of a promise, then  
>> all sorts of code would fail where I really wanted to evaluate the  
>> arg before extracting the environment.
> 
> Thank you Duncan, for the very clear explanation.
> 
> Ok, so the substitute "breaks through" the promise of expr, returning  
> as a language object the promise of er, and there's no easy way to  
> break through that. I ended up with the following, somewhat uglier  
> than I wanted, code, which seems to do what I need in this case, and  
> hopefully will still work in the more general case I want it to. The  
> idea was to break through the er promise in bar, before sending it  
> over to foo. Then foo receives simply an expression, which it can  
> then evaluate. Though I seem to have had to work a bit harder on that  
> part than I expected to. Perhaps there's an easier way? Or things  
> that can go seriously wrong with this way?
> 
> foo <- function(fr, expr) {
>    ..obj <- list(.=fr)
>    ..expr <- substitute(expr)
>    ..txt <- parse( text=paste("substitute(",..expr,")") )

I think you want

..txt <- parse( text=paste("substitute(",deparse(..expr),")") )

here, but it's even better not to go through the deparse-parse cycle:

..txt <- bquote( substitute( .(..expr) ) )

The main thing that could go wrong is the evaluation of er might not be 
right.  Just because it is an argument to bar doesn't mean bar's frame 
or parent.frame() is the right place to evaluate it.

To check for errors, I'd introduce like-named variables at lots of 
levels, and then put them into the expression you were evaluating in 
such a way that you can tell which one was found.  For example, put
x <- "foo" into foo(), x <- "bar" into bar(), and x <- "global" into the 
global environment.  Then evaluate some expression that prints x and 
make sure you see the right one.

Duncan Murdoch

>    ..expr <- eval(..txt, ..obj, parent.frame())
>    ..expr <- eval(..expr, parent.frame())
>    eval(..expr, ..obj)
> }
> bar <- function(parent, er, ...) {
>    .fr=parent
>    g <- substitute(er)
>    foo(.fr, g)
> }
> 
>  > foo(5,.)
> [1] 5
>  > bar(5,.)
> [1] 5
> 
> 
>> Duncan Murdoch
> 
> Haris Skiadas
> Department of Mathematics and Computer Science
> Hanover College
> 
> ______________________________________________
> R-help at r-project.org mailing list
> https://stat.ethz.ch/mailman/listinfo/r-help
> PLEASE do read the posting guide http://www.R-project.org/posting-guide.html
> and provide commented, minimal, self-contained, reproducible code.



More information about the R-help mailing list