Skip to content

merging environments

5 messages · Ben Bolker, Duncan Murdoch, Gabor Grothendieck +1 more

#
Despite the spirited arguments of various R-core folks
who feel that mle() doesn't need a "data" argument, and
that users would be better off learning to deal with function
closures, I am *still* trying to make such things work
in a reasonably smooth fashion ...

   Is there a standard idiom for "merging" environments?
i.e., suppose a function has an environment that I want
to preserve, but _add_ the contents of a data list --
would something like this do it? Is there a less ugly
way?

x <- 0
y <- 1
z <- 2

f <- function() {
     x+y+z
}

f2 <- function(fun,data) {
     L <- ls(pos=environment(fun))
     mapply(assign,names(data),data,
                      MoreArgs=list(envir=environment(fun)))
     print(ls(pos=environment(fun)))
}

f2(f,list(a=1))


-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 252 bytes
Desc: OpenPGP digital signature
Url : https://stat.ethz.ch/pipermail/r-devel/attachments/20080307/beda69c0/attachment.bin
#
On 3/7/2008 2:02 PM, Ben Bolker wrote:
One way is to set one as the parent of the other.  If they both already 
have non-empty parents, you're out of luck.
Luckily lists and data.frames don't have parents, so you can make a new 
environment, put the elements of data into it, and set the old 
environment as its parent.  That's sort of like what you did, but 
slightly different, and with fewer bad side effects:

bothenvs <- function(fun,data) {
      newenv <- new.env(hash=TRUE, parent=environment(fun))
      mapply(assign,names(data),data,
                       MoreArgs=list(envir=newenv))
      newenv
}

It would sure be nice if as.environment() took a list as an arg and 
turned it into an environment, but no such luck.

Duncan Murdoch
#
You can either use the facilities of environments or
the proto package can do this if you take advantage of the fact
that a proto object is an environment:
<environment: R_GlobalEnv>
attr(,"class")
[1] "proto"       "environment"
[1] "a" "f"

which does what you ask although you might prefer to create
a new environment/proto object with f in it to avoid explicit
environment manipulation:

# create proto object, i.e. environment, with a and f in it
p <- proto(a = 1, f = function(.) {})

# and you can add more variables later:
p$b <- 2
p[["c"]] <- 3
ls(p)
with(p, ls(environment(f))) # same

or with environments not using proto:

# create an unnamed environment and put a and f in
# adding b and c to it later
f <- local({ a <- 1; function(){} })
environment(f)$b <- 2
environment(f)[["c"]] <- 3

ls(environment(f))

2008/3/7 Ben Bolker <bolker at zoo.ufl.edu>:
#
2008/3/7 Ben Bolker <bolker at zoo.ufl.edu>:
I think you're doomed to be ugly if you don't use closures - I think
any explicit manipulation of environments is worse than the implicit
manipulation by closures.

f <- function(data) with(data, x + y + z)
f2 <- function(fun, data) function() fun(data)

f2(f, list(x = 10))()

Although it would be even nicer if you could do:

f <- function()  x + y + z
f2 <- function(fun, data) function() with(data, fun())

but I think that's confusing different types of scoping.

Hadley
#
On Fri, Mar 7, 2008 at 3:15 PM, hadley wickham <h.wickham at gmail.com> wrote:
This last one is close to what you can do with proto and is referred
to as the method of proxies here:
http://r-proto.googlecode.com/files/prototype_approaches.pdf

f <- function() x + y + z
f2 <- function(fun, ...) with(proto(environment(fun), ..., g = fun), g())
f2(f, x = 1, y = 2, z = 3)

The proto call creates an anonymous proto object whose parent is
the parent of fun.  The anonymous proto object contains the ...
arguments to f2 and g.    g is just fun with its environment reset to
the anonymous proto object. We then call g.