What is the mechanism that does `+` work if it is defined in + in an empty environment?

Here I create an invaluable expression:

e2 <- expression(x+10) 

If I put an environment in which x is defined as

 env <- as.environment(list(x=20)) eval(e2,env) 

R will report an error:

 Error in eval(expr, envir, enclos) : could not find function "+" 

This is understandable, since env is an environment created from scratch, that is, it does not have a parent environment where + defined.

However, if I put + in a list that will be converted to an environment like this

 env <- as.environment(list(x=20,`+`=function(a,b) {a+b})) eval(e2,env) 

The rating works correctly and gives 30.

However, when I define + in the list, this is a binary function whose body also uses +, which is defined in {base} . I know that returning a function is lazily evaluated in R, but why might this work? If a+b in the function body is evaluated lazily when I call eval for e2 inside env , although + is defined in this environment, which does not have a parent environment, it should still call + by itself, which should end in an infinite loop. Why is this not happening? What is the mechanism here?

+6
source share
1 answer

When you define the environment here:

 env <- as.environment(list(x=20,`+`=function(a,b) {a+b})) 

then the definition of the function is actually defined in .GlobalEnv (namely, where the definition is executed. You can check this:

 $ environment(env$`+`) <environment: R_GlobalEnv> 

This remark is worth a little thought: a function can be a member of the environment x , but belong to y (where β€œbelongs” means that its object search uses y , not x ).

And .GlobalEnv knows about + , as it is defined somewhere in its parents (accessible via search() ).

By the way, if you used list2env instead of as.environment , your source code would work:

 $ env = list2env(list(x = 20)) $ eval(e2, env) 30 

The reason is that, unlike as.environment , list2env by default uses the current environment as the parent new environment (this can be controlled using the parent argument). as.environment in contrast uses an empty environment (when creating an environment from a list).

+4
source

All Articles