[R] Understanding eval

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


On 23/12/2007 9:15 AM, Duncan Murdoch wrote:
> 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 ...

Sorry, this wasn't written clearly:  This was a response to your second 
question, not a continuation of the bquote() suggestion.

Duncan Murdoch


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.
> 
> ______________________________________________
> 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