[R] `eval' and environment question

Joerg van den Hoff j.van_den_hoff at fzd.de
Tue Nov 13 15:48:57 CET 2007


On Tue, Nov 13, 2007 at 09:04:25AM -0500, Duncan Murdoch wrote:
> On 11/13/2007 8:39 AM, Joerg van den Hoff wrote:
> >my   understanding   of   `eval'   behaviour   is  obviously
> >incomplete.
> >
> >my    question:   usually   `eval(expr)'   and   `eval(expr,
> >envir=parent.frame())' should be identical.   why  does  the
> >last  `eval'  (yielding `r3') in this code _not_ evaluate in
> >the local environment of function  `f'  but  rather  in  the
> >global environment (if `f' is called from there)?]
> 
> Because you said "parent.frame()" as its value.  The values of 
> explicitly passed arguments are evaluated in the frame of the caller, 
> i.e. in the evaluation frame of f().  There, parent.frame() is the frame 
> that called f(), i.e. the global environment.
> 
> Default values for parameters are evaluated in the evaluation frame of 
> the function using them.  So if you don't specify envir in a call to 
> eval(), parent.frame() is evaluated in the eval evaluation frame, and it 
> refers to whatever function called eval().
> 
> >
> >#----------------------------------------------------------
> >f <- function () {
> >
> >   a <- 1
> >   x <- 1
> >
> >   model        <- y ~ a * x
> >   fitfunc      <- deriv(model[[3]], c("a"), c("a", "x"))
> >   call.fitfunc <- c(list(fitfunc), as.name("a"), as.name("x"))
> >   call.fitfunc <- as.call(call.fitfunc)
> >
> >   curenv <- environment()
> >
> >   cat(" eval(call.fitfunc)\n")
> >   r1 = eval(call.fitfunc)
> >   str(r1)
> >
> >   cat(" eval(call.fitfunc, envir = curenv)\n")
> >   r2 = eval(call.fitfunc, envir = curenv)
> >   str(r2)
> >
> >   cat(" eval(call.fitfunc, envir = parent.frame())\n")
> >   r3 = eval(call.fitfunc, envir = parent.frame())
> >   str(r3)
> >
> >}
> >#----------------------------------------------------------
> >
> >
> >`args(eval)' yields:
> >
> >"function (expr, envir = parent.frame(), enclos = if (is.list(envir) || 
> >    is.pairlist(envir)) parent.frame() else baseenv())"
> >
> >
> >and  the manpage says the same: the default value of `envir'
> >is `parent.frame()'. so I  would  expect  (lazy  evaluation)
> >that  providing  the  default argument explicitely should'nt
> >alter the behaviour. where is my error?
> 
> Lazy evaluation affects the order of evaluation, but not the evaluation 
> environment.  If you pass an argument to a function, it will be 
> evaluated in your environment.  If you rely on the function to provide a 
> default, that will be evaluated in the environment of the function.

OK,  I  see  (and  it's  probably  all  in the documentation
somewhere). it's obvious once it's explained. but why _does_
the following work?

#--------------------------------------------
f <- function () {

   x <- 1

   curenv <- environment()

   cat(" eval(x)\n")
   r1 = eval(x)
   str(r1)

   cat(" eval(x, envir = curenv\n")
   r2 = eval(x, envir = curenv)
   str(r2)

   cat(" eval(x, envir = parent.frame())\n")
   r3 = eval(x, envir = parent.frame())
   str(r3)
#--------------------------------------------

now, the third eval _yields_ a result, although according to
your explanation `x' should be searched for  in  the  global
env.  (as was actually the case in my initial example). what
am I missing this time? is `x' copied into  the  call  as  a
constant  and  no  longer  searched at all or something like
that?

}
> 
> It all makes sense:  when you write the function you've got no idea what 
> the caller will be like, so you can't refer to its environment in your 
> defaults.  On the other hand, when you call a function you shouldn't 
> care what its internal environment looks like, so your arguments should 
> be evaluatable in your own environment, and their value shouldn't change 
> just because the implementation of the function changes.

I  presume,  one  could  argue for the opposite behaviour as
well? maybe there is some language out there actually  doing
it  the  other  way (passing the unevaluated argument string
and leaving everything to the called function)?   I will try
to  remember  this  "detail" and then it's fine with me, but
from the outset it's quite irritating that  writing  down  a
call  which  is  identical to the definition of the function
(including its defaults) does not necessarily yield the same
result as when the defaults are really used.

> 
> This all gets more complicated with formulas in functions like nls(). 
> Formulas normally have an environment attached to them too, but 
> sometimes people mess with it, and then things can go crazy.

hope you're not meaning me... 


thanks

joerg
> 
> Duncan Murdoch
> >
> >regards,
> >
> >joerg
> >
> >______________________________________________
> >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