philchalmers
philchalmers

Reputation: 747

Attaching object without using attach() or with()

This may appear as a strange request, but I'm looking to essentially attach an object temporarily so that individual elements can be extracted from said object, but without actually using attach() or with(). For instance, I'm well aware that these two approaches are fine to index a data.frame elements by name"

obj <- data.frame(N=2, sd=1)

myfun <- function(obj){
    N2 <- obj$N^2
    rnorm(N2, obj$sd)
}
myfun(obj)

myfun2 <- function(obj){
    with(obj, {
        N2 <- N^2
        rnorm(N2, sd)
    })
}
myfun2(obj)

However, what I want is something more general, where the form can be

# wanted
myfun3 <- function(){
    N2 <- N^2
    rnorm(N2, sd)
}
with(obj, myfun3()) #this is the idea but clearly doesn't work

so that explicitly indexing the elements of obj is not required, and wrapping the whole statement in a with() function can be avoided. Obviously myfun3() doesn't locate the internals of obj, but I would like it to. The following works fine and is exactly what I want from a functional standpoint, but is far from kosher:

attach(obj)
myfun3()
detach(obj)

Attaching is generally considered bad, and for my purpose this code has to work within an R package, so attach() isn't even allowed (as well, it be nested within another function which can be run in parallel....so exporting to the Global Environment likely is not a good solution).

Ultimately, I would like this all to work as follows in a safe parallel computing environment

library(parallel)
cl <- makeCluster()
parfun <- function(index, obj, myfun){
    out <- with(obj, myfun())
    out
}    
parSapply(cl=cl, 1:100, parfun, obj=obj, myfun=myfun3)

Any thoughts would be greatly appreciated.

Upvotes: 0

Views: 151

Answers (1)

Jthorpe
Jthorpe

Reputation: 10167

How about:

do.with  <-  function(context,fun,args=list()){
    env  <-  as.environment(context)
    parent.env(env)  <-  environment(fun)
    environment(fun)  <- env
    do.call(fun,args)
}

context = list(x=1,y=2)
add = function() x + y
do.with(context,add)


context = list(x=2)
parameters = list(y=5)
mult = function(y) x * y
do.with(context,mult,parameters)

Upvotes: 1

Related Questions