merging environments

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

merging environments

Ben Bolker-2

   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))



______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

signature.asc (260 bytes) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: merging environments

Duncan Murdoch
On 3/7/2008 2:02 PM, Ben Bolker wrote:
>    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?

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.

> 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))

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

>
>
>
>
> ------------------------------------------------------------------------
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: merging environments

Gabor Grothendieck
In reply to this post by Ben Bolker-2
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:

> library(proto)
> f <- function() {}
> # put a into the environment of f
> do.call(proto, c(list(a = 1), envir = environment(f)))
<environment: R_GlobalEnv>
attr(,"class")
[1] "proto"       "environment"
> ls(environment(f))
[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 <[hidden email]>:

>
>   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))
>
>
>
> ______________________________________________
> [hidden email] mailing list
> https://stat.ethz.ch/mailman/listinfo/r-devel
>
>

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: merging environments

hadley wickham
In reply to this post by Ben Bolker-2
2008/3/7 Ben Bolker <[hidden email]>:

>
>    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))

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
--
http://had.co.nz/

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel
Reply | Threaded
Open this post in threaded view
|

Re: merging environments

Gabor Grothendieck
On Fri, Mar 7, 2008 at 3:15 PM, hadley wickham <[hidden email]> wrote:

> 2008/3/7 Ben Bolker <[hidden email]>:
> >
>
> >    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))
>
> 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())


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.

______________________________________________
[hidden email] mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel