Great environment, functional environment, etc. In R

I have a few questions about various function environments. Take the following example:

environment(sd) # <environment: namespace:stats> 

Namespace: statistics indicate sd environment?

 pryr::where(sd) # <environment: package:stats> 

Does the package indicate: statistics indicate the sd function binding environment?

According to Advanced R by Hadley Wickham : "The environment belongs to the function and never changes ..."

But the environment of the function can be changed as follows:

 new.env <- new.env() environment(f) <- new.env 

The property property of a function points to a function that runs the environment, right? An online article on R Media Search Through Media

Summing up your questions:

  • Is it possible to change the environment or not?
  • What are two different stats package environments?
  • What is a feature environment?

It is similar to the previous post here .

+5
source share
2 answers

TL; DR:

  • indeed, you can change the environment. Hadley probably talked about packed features.
  • environment and binding environment. You were right.
  • what is the execution environment. It exists only for the execution time of a function.

Functional environments

When discussing a function, you should distinguish 4 different environments:

  • the binding environment is the environment in which the function is located (i.e. where its name exists). This is where the actual binding of the object to its name is performed. find() provides you with a binding environment.
  • Environment is the environment in which the function was originally created. This is not necessarily the same as the binding environment (see Examples below). environment() provides the environment.
  • the local environment is the environment inside the function. You call it a runtime.
  • the parent frame or calling environment is the environment from which the function is called.

Why does it matter

Each environment has a specific function:

  • The binding environment is the environment in which you will find this feature.
  • the local environment is the first environment where R searches for objects.
  • general rule: if R does not find the object in the local environment, it looks in the environment and so on. The last environment is always emptyenv() .
  • the parent frame is where R searches for the value of the objects passed as arguments.

You can change the environment

In fact, you can change the environment. This is an environment of a function from a package that you cannot change. In this case, you do not change the environment, you actually create a copy in the new environment:

 > ls() character(0) > environment(sd) <environment: namespace:stats> > environment(sd) <- globalenv() > environment(sd) <environment: R_GlobalEnv> > ls() [1] "sd" > find("sd") [1] ".GlobalEnv" "package:stats" # two functions sd now > rm(sd) > environment(sd) <environment: namespace:stats> 

In this case, the second sd has a global environment as an inclusion and binding environment, but the original sd is still inside the package environment, and the environment is still the namespace of this package

Confusion may occur if you do the following:

 > f <- sd > environment(f) <environment: namespace:stats> > find("f") [1] ".GlobalEnv" 

What's going on here? The environment is still the "statistics" of the namespace. This is where the function is created. However, the binding environment is now a global environment. Where the name "f" is attached to the object.

We can change the environment to a new environment e . If you check now, the environment will become e , but e itself is empty. f is still connected in a global environment.

 > e <- new.env() > e <environment: 0x000000001852e0a8> > environment(f) <- e > find("f") [1] ".GlobalEnv" > environment(f) <environment: 0x000000001852e0a8> > ls(e) character(0) 

Environment e is a global environment. Thus, f still works as if its shell were a global environment. It contains the e environment, so if something is not found in e , the function looks into the global environment and so on.

But since e is the environment, R calls the parent environment.

 > parent.env(e) <environment: R_GlobalEnv> > f(1:3) [1] 1 

Namespaces and Package Environments

This principle is also used in trick packages:

  • a function is created in the namespace. This is an environment that is surrounded by the namespaces of other imported packages and, ultimately, the global environment.
  • the binding for the function is created in the package environment. This is an environment that covers a global environment and possible other packages.

The reason for this is simple: objects can only be found inside the environment in which you are located, or in environments.

  • a function must be able to find other functions (objects), so the local environment should be enclosed, possibly in the namespaces of other packages it imports, the base package, and finally, the global environment.
  • the function must be found from the global environment. Therefore, the binding (i.e., the name of the function) must be in an environment that is surrounded by a global environment. This is a package environment (NOT a namespace!)

Illustration:

enter image description here

Now suppose you are creating an environment with an empty environment as the parent. If you use this as the environment for a function, nothing works. Because now you have bypassed all the package environments, so you can no longer find one function.

 > orphan <- new.env(parent = emptyenv()) > environment(f) <- orphan > f(1:3) Error in sqrt(var(if (is.vector(x) || is.factor(x)) x else as.double(x), : could not find function "sqrt" 

Parent frame

Here it becomes interesting. A parent frame or calling environment is an environment in which values โ€‹โ€‹passed as arguments are viewed. But this parent frame may be the local environment of another function. In this case, R first looks in this local environment of this other function, and then in the environment of the calling function and, thus, up to the global environment, the environment of attached packets, until it reaches an empty environment. That the failure "object not found".

+14
source

environment(function) provides a function environment (i.e., a closure) that is assigned a pointer to the environment in which the function is defined. This convention is called lexical reach, and it allows you to use patterns such as factory. Here is a simple example

 factory <- function(){ # get a reference to the current environment -- ie the environment # that was created when the function `factory` was called. envir = environment() data <- 0 add <- function(x=1){ # we can use the lexical scoping assignment operator to re-assign the value of data data <<- data + x # return the value of the lexically scoped variable `data` return(data) } return(list(envir=envir,add=add)) } L = factory() # check that the environment for L$add is the environment in which it was created identical(L$envir,environment(L$add)) #> TRUE L$add() #> 1 L$add(3) #> 4 

note that we can reassign the value of data in the environment using assign() as follows:

 assign("data",100,L$envir) L$add() #> 101 

In addition, when we call the factory() function again, a new new environment is created and assigned as a closure for the functions that are defined in the function call, which allows us to separate the foo $ add () functions according to their individual conditions:

 M = factory() M$add() #> 1 #> 2 L$add() #> 102 

The above factory function illustrates the relationship between this function and the environment by continuing to search for a variable (and using the scope assignment operator, while the following illustrates the relationship between the local environment and the calling frame through Promises, as R passes the variables in the function call.

In particular, when you call a function, R creates Promises for the value of the passed variables and expressions. These Promise values โ€‹โ€‹are passed (copied) from the variable / expression, evaluating the Promise in the context of the calling environment when the force() 'd parameter is used or not - and not before!

For example, this factory function takes a parameter that is saved as a promise until the return function is called:

 factory2 <- function(x){ out <-function(){ return(x) } return(out) } 

Now factory2 behaves intuitively in some cases:

 y = 1 f = factory2(y) f() #> 1 

but not in others:

 y = 1 h = factory2(y) y = 2 h() #> 2 

because the promise of the expression y not evaluated until the expression h() is called, and in the second example, the value of y is 2! Of course, now that the value has been copied from the calling environment to the local environment through a Promise evaluation, changing the value of y will not affect the value returned by h() :

 y = 3 h() #> 2 
+3
source

Source: https://habr.com/ru/post/1268650/


All Articles