How can I customize the character search path when evaluating an expression?

In the case when I need to customize the search path for some characters. For example, when I evaluate an expression f(x,y,z)

, I need to evaluate it in the following chain of environments:

First, find the characters in env1

where x

and y

determined, but f

and z

are not.

then find f

and z

at env2

where both are defined.

The problem is that env1

both are env2

not self-defined, meaning their parent environment is determined when I can use them.

In this particular case, I can manually call exists

and get

to find those symbols. But this doesn't seem to work in the general case where the expression is in user input and is not known in advance.

Is there a general and quick way of working for any custom input expression, so that this expression evaluates within a series of a given environment with inherits = FALSE

the exception of the latter. Suppose the function is called evalc

, then the usage could be:

evalc(quote(f(x,y,z)), env1, env2, env3)

where a number of environments are given. For env1

and env2

symbols appear with inherits = FALSE

; but for the env3

characters are scanned with inherits = TRUE

.

+3


source to share


1 answer


1) Do you really need it inherits = FALSE

? This works differently:

esub <- function(...) do.call(substitute, list(...))
evalc <- function(expr, env1, env2, env3 = parent.frame()) {
   eval(esub(esub(expr, env1), env2), env3)
}

 # test
 env1 <- list2env(list(x = 1, y = 2))
 env2 <- list2env(list(f = function(...) list(...), z = 3))
 evalc(quote(f(x, y, z)), env1, env2)

      

2) If you really need inherits = FALSE

, then we will copy each environment to a new environment, in which any empty environment will be the parent:

evalc <- function(expr, env1, env2, env3 = parent.frame()) {
   e1 <- list2env(as.list(env1))
   e2 <- list2env(as.list(env2))
   parent.env(e1) <- parent.env(e2) <- emptyenv()
   eval(esub(esub(expr, e1), e2), env3)
}

      

3) If we have an unknown number of media:



evalc <- function(expr, ..., env = parent.frame()) {
   for(e in list(...)) {
      ee <- list2env(as.list(e))
      parent.env(ee) <- emptyenv()
      expr <- esub(expr, ee)
   }
   eval(expr, env)
}

      

4) Here is another solution to avoid copying. This requires that you could change the parent item env1

, env2

...

evalc <- function(expr, ..., env = parent.frame()) {
   for(e in list(...)) {
      p <- parent.env(e)    
      parent.env(e) <- emptyenv()
      expr <- esub(expr, e)
      parent.env(e) <- p
   }
   eval(expr, env)
}

      

Update added 2, 3 and 4.

+1


source







All Articles