[R] eval parent.frame() twice
Duncan Murdoch
murdoch at stats.uwo.ca
Fri Aug 7 14:56:35 CEST 2009
On 8/7/2009 7:36 AM, Rune Schjellerup Philosof wrote:
> Peter Dalgaard skrev:
>> Rune Schjellerup Philosof wrote:
>>
>>> Hi
>>>
>>> I want to use a function (update) that in its body uses
>>> eval(call, parent.frame())
>>>
>>> I would like to use this function in a function that does not contain
>>> the variables referred to in 'call'. Those variables are instead in the
>>> parent.frame() of my function (named 'second' below)
>>>
>>> Like this:
>>> a <- 2
>>>
>>> evalu <- function(obj) {
>>> call <- obj$call
>>> eval(call, parent.frame())
>>> }
>>> first <- function() {
>>> a <- 3
>>> obj <- list(call=expression(a))
>>> second(obj)
>>> }
>>> second <- function(obj) {
>>> eval(evalu(obj), parent.frame())
>>> }
>>>
>>> first() #returns 2, but I want 3.
>>>
>>>
>>> How do I change 'second' such that the value of 'a' from 'first' is
>>> returned?
>>>
>>>
>>
>> You could use the "n" argument to parent.frame (or eval.parent) inside
>> "evalu" and go two generations back instead of one. Somewhat neater, you
>> could pass the desired environment directly to evalu, as in
>>
>> e <- parent.frame()
>> evalu(obj, e)
>>
>> (I'm not sure it is actually needed to separate out the calculation of
>> "e", but I tend to be paranoid about evaluating parent.frame() in
>> function arguments.)
>>
>>
>>
>
> Thanks for the answer, but it isn't what I need.
> 'evalu' is a replacement for a function that I cannot change
> (update.default).
> My question is: How do I accomplish this by only changing 'second'?
I don't think there is any clean way to do that, but you can call
update.default with evaluate=FALSE, and then evaluate the result in
whatever environment you like.
If you are determined to do it uncleanly, then one way would be to
create a little function that has no names that should clash to call
update.default, and set its environment to the environment in which you
want the evaluation to happen. E.g.
second <- function(obj, formula) {
my.update.default <- function(.safe.obj, .safe.formula) {
update.default(.safe.obj, .safe.formula)
}
environment(my.update.default) <- parent.frame()
my.update.default(obj, formula)
}
If your user happens to use ".safe.obj" or ".safe.formula" as the name
of a variable in their model, this will fail, but otherwise it should
work, because update.default will look at the locals of
my.update.default first, before it goes to the parent, which is
parent.frame(). If you need to pass more arguments to update.default you
need to worry about their name clashes as well.
Personally, I'd stick to the clean solution. You could try lobbying for
a change to update.default, but I think you'd fail, because the clean
solution is available.
Duncan Murdoch
>>> }
More information about the R-help
mailing list