Every environment has a parent, another environment. Only one environment doesn’t have a parent: the empty environment.
It’s rare to talk about the children of an environment because there are no back links: given an environment we have no way to find its children.
Generally, an environment is similar to a list, with four important exceptions:
- Every object in an environment has a unique name.
- The objects in an environment are not ordered (i.e. it doesn’t make sense to ask what the first object in an environment is).
- An environment has a parent.
- Environments have reference semantics.
There are four special environments:
- The globalenv(), or global environment, is the interactive workspace. This is the environment in which you normally work. The parent of the global environment is the last package that you attached with library() or require().
- The baseenv(), or base environment is the environment of the base package. Its parent is the empty environment.
- The emptyenv(), or empty environment, is the ultimate ancestor of all environments, and the only environment without a parent.
- The environment() is the current environment.
search() lists all parents of the global environment. This is called the search path because objects in these environments can be found from the top-level interactive workspace. It contains one environment for each attached package and any other objects that you’ve attach()ed. It also contains a special environment called Autoloads which is used to save memory by only loading package objects (like big datasets) when needed.
You can access any environment on the search list using as.environment().
For example, as.environment("package:stats").
To create an environment manually, use new.env(). You can list the bindings in the environment’s frame with ls() and see its parent with parent.env().
Another useful way to view an environment is ls.str(). It is more useful than str() because it shows each object in the environment. Like ls(), it also has an all.names argument.
Given a name, you can extract the value to which it is bound with $, [[, or get():
- $ and [[ look only in one environment and return NULL if there is no binding associated with the name.
- get() uses the regular scoping rules and throws an error if the binding is not found.
Given a name, where() finds the environment where that name is defined, using R’s regular scoping rules.
The definition of where() is straightforward. It has two arguments: the name to look for (as a string), and the environment in which to start the search.
where <- function(name, env = parent.frame())
{
if (identical(env, emptyenv()))
{
# Base case
stop("Can't find ", name, call. = FALSE)
} else if (exists(name, envir = env, inherits = FALSE)) {
# Success case
env
} else {
# Recursive case
where(name, parent.env(env))
}
}
The four types of environments associated with a function are enclosing, binding, execution, and calling.
The enclosing environment is the environment where the function was created. Every function has one and only one enclosing environment. For the three other types of environment, there may be 0, 1 or many environments associated with each function:
- Binding a function to a name with <- defines a binding environment.
- Calling a function creates an ephemeral execution environment that stores variables created during execution.
- Every execution environment is associated with a calling environment, which tells you where the function was called.
When a function is created, it gains a reference to the environment where it was made. This is the enclosing environment and is used for lexical scoping. You can determine the enclosing environment of a function by calling environment() with a function as its first argument.
No comments:
Post a Comment