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

>>> }

______________________________________________
[email protected] 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.

Reply via email to