lexical scope in R - r

I recently learned that R has both lexical and dynamical scoping available, but that it uses lexical scope by default. The next case really confused me:
> x <- 1
> f <- function(y) { x + y }
> f(5) # we expect 6
[1] 6
> x <- 10
> f(5) # shouldn't we again expect 6?
[1] 15
Shouldn't f be evaluated using the environment where (and at the time!) it was defined and not where it was called ? How is this lexical scope? Thanks!

f <- function(y) { x + y }
was defined in the global environment and so for the parts not defined in the function itself (i.e.x), R looks to the global environment for them.
a=1
b=2
f<-function(x)
{
a*x + b
}
g<-function(x)
{
a=2
b=1
f(x)
}
# compare f(2) and g(2)
This example above is from here and gives a good discussion. Main point being, f() within g() ignores the definitions of a and b in g().
From the wiki on "Scope"
In object-oriented programming, dynamic dispatch selects an object method at runtime, though whether the actual name binding is done at compile time or run time depends on the language.

Related

meta-programming and the substitute function in R

f <- function() {
x <- 6 + 4
substitute(x)
}
f()
The above will output:
[1] 10
However, the below:
x <- 6 + 4
substitute(x)
outputs:
x
Why are they different?
#akrun's answer demonstrates how to get it to resolve, but I think the answer to your question of "Why?" is in ?substitute, where it says in the Details:
If it is an ordinary variable, its value is substituted, unless env is .GlobalEnv in which case the symbol is left unchanged.
(Emphasis mine.) When you are executing this on the default prompt >, you are in the global environment. Not so in your first example, within the function's namespace. (As to "Why did R-core decide on this behavior?", I do not think I am qualified to answer or even speculate.)
The evaluation is not happening
eval(substitute(x))
#[1] 10
As #r2evans showed the documentation description, we can test it on a new environment to see this in action
# create the object in another environment
e1 <- new.env()
e1$x <- 6 + 4
substitute(x) # here x is looked in the global space
#x
substitute(x, env = e1) # specify the `env` and looks for the local env
#[1] 10

Why is this simple function not working?

I first defined new variable x, then created function that require x within its body (not as argument). See code below
x <- c(1,2,3)
f1 <- function() {
x^2
}
rm(x)
f2 <- function() {
x <- c(1,2,3)
f1()
}
f(2)
Error in f1() : object 'x' not found
When I removed x, and defined new function f2 that first define x and then execute f1, it shows objects x not found.
I just wanted to know why this is not working and how I can overcome this problem. I do not want x to be name as argument in f1.
Please provide appropriate title because I do not know what kind of problem is this.
You could use a closure to make an f1 with the desired properties:
makeF <- function(){
x <- c(1,2,3)
f1 <- function() {
x^2
}
f1
}
f1 <- makeF()
f1() #returns 1 4 9
There is no x in the global scope but f1 still knows about the x in the environment that it was defined in.
In short: Your are expecting dynamic scoping but are a victim of R's lexical scoping:
dynamic scoping = the enclosing environment of a command is determined during run-time
lexical scoping = the enclosing environment of a command is determined at "compile time"
To understand the lookup path of your variable x in the current and parent environments try this code.
It shows that both functions do not share the environment in with x is defined in f2 so it can't never be found:
# list all parent environments of an environment to show the "search path"
parents <- function(env) {
while (TRUE) {
name <- environmentName(env)
txt <- if (nzchar(name)) name else format(env)
cat(txt, "\n")
if (txt == "R_EmptyEnv") break
env <- parent.env(env)
}
}
x <- c(1,2,3)
f1 <- function() {
print("f1:")
parents(environment())
x^2
}
f1() # works
# [1] "f1:"
# <environment: 0x4ebb8b8>
# R_GlobalEnv
# ...
rm(x)
f2 <- function() {
print("f2:")
parents(environment())
x <- c(1,2,3)
f1()
}
f2() # does not find "x"
# [1] "f2:"
# <environment: 0x47b2d18>
# R_GlobalEnv
# ...
# [1] "f1:"
# <environment: 0x4765828>
# R_GlobalEnv
# ...
Possible solutions:
Declare x in the global environment (bad programming style due to lack of encapsulation)
Use function parameters (this is what functions are made for)
Use a closure if x has always the same value for each call of f1 (not for beginners). See the other answer from #JohnColeman...
I strongly propose using 2. (add x as parameter - why do you want to avoid this?).

R programming functions

I'm learning R programming. I'm unable to understand how function within function works in R. Example:
f <- function(y) {
function() { y }
}
f()
f(2)()
I'm not able to understand why $f() is not working and showing following message:
function() { y }
<environment: 0x0000000015e8d470>
but when I use $f(4)() then it is showing answer as 4.
Please explain your answer in brief so that I can understand it easily.
For a more general case, let's change the "inner" function a little bit:
f <- function(y) {
function(x) { y + x}
}
Now f(2) returns a function that adds 2 to its argument. The value 2 is kept in the function's environment:
> f(2)
function(x) { y + x}
<environment: 0x0000000015a690f0>
> environment(f(2))$y
[1] 2
.. and you can change it if you really want to but for this you need to assign a name to the output of f():
> g <- f(2)
> environment(g)$y
[1] 2
> environment(g)$y <- 3
> g(1)
[1] 4
Why do you need a g here? Because otherwise, the environment created with f(2) is garbage collected immediately, so there's no way to access it:
> environment(f(2))$y<-4
Error in environment(f(2))$y <- 4 :
target of assignment expands to non-language object
This won't affect the case when you use, say, f(2) only once:
> f(2)(3)
[1] 5
The reason is that the inner function behave as the answer of the outer one son by just doing f(), the result is a function. The best way is to call it double f(3)() as the inner function doesn't take any argument.

Using the same argument names for a function defined inside another function

Why does
f <- function(a) {
g <- function(a=a) {
return(a + 2)
}
return(g())
}
f(3) # Error in a + 2: 'a' is missing
cause an error? It has something to do with the a=a argument, particularly with the fact that the variable names are the same. What exactly is going on?
Here are some similar pieces of code that work as expected:
f <- function(a) {
g <- function(a) {
return(a + 2)
}
return(g(a))
}
f(3) # 5
f <- function(a) {
g <- function(g_a=a) {
return(g_a + 2)
}
return(g())
}
f(3) # 5
g <- function(a) a + 2
f <- function(a) g(a)
f(3) # 5
The problem is that, as explained in the R language definition:
The default arguments to a function are evaluated in the evaluation frame of the function.
In your first code block, when you call g() without any arguments, it falls back on its default value of a, which is a. Evaluating that in the "frame of the function" (i.e. the environment created by the call to g()), it finds an argument whose name matches the symbol a, and its value is a. When it looks for the value of that a, it finds an argument whose name matches that symbol, and whose value is a. When...
As you can see, you're stuck in a loop, which is what the error message is trying to tell you:
Error in g() :
promise already under evaluation: recursive default argument reference or
earlier problems?
Your second attempt, which calls g(a) works as you expected, because you've supplied an argument, and, as explained in the same section of R-lang:
The supplied arguments to a function are evaluated in the evaluation frame of the calling function.
There it finds a symbol a, which is bound to whatever value you passed in to the outer function's formal argument a, and all is well.
The problem is the a=a part. An argument can't be its own default. That is a circular reference.
This example may help clarify how it works:
x <- 1
f <- function(a = x) { x <- 2; a }
f()
## [1] 2
Note that a does not have the default 1; it has the default 2. It looks first in the function itself for the default. In a similar way a=a would cause a to be its own default which is circular.

Getting the parse tree for a predefined function in R

I feel as if this is a fairly basic question, but I can't figure it out.
If I define a function in R, how do I later use the name of the function to get its parse tree. I can't just use substitute as that will just return the parse tree of its argument, in this case just the function name.
For example,
> f <- function(x){ x^2 }
> substitute(f)
f
How should I access the parse tree of the function using its name? For example, how would I get the value of substitute(function(x){ x^2 }) without explicitly writing out the whole function?
I'm not exactly sure which of these meets your desires:
eval(f)
#function(x){ x^2 }
identical(eval(f), get("f"))
#[1] TRUE
identical(eval(f), substitute( function(x){ x^2 }) )
#[1] FALSE
deparse(f)
#[1] "function (x) " "{" " x^2" "}"
body(f)
#------
{
x^2
}
#---------
eval(parse(text=deparse(f)))
#---------
function (x)
{
x^2
}
#-----------
parse(text=deparse(f))
#--------
expression(function (x)
{
x^2
})
#--------
get("f")
# function(x){ x^2 }
The print representation may not display the full features of the values returned.
class(substitute(function(x){ x^2 }) )
#[1] "call"
class( eval(f) )
#[1] "function"
The function substitute can substitute in values bound to an environment. The odd thing is that its env argument does not possess a default value, but it defaults to the evaluation environment. This behavior seems to make it fail when the evaluation environment is the global environment, but works fine otherwise.
Here is an example:
> a = new.env()
> a$f = function(x){x^2}
> substitute(f, a)
function(x){x^2}
> f = function(x){x^2}
> environment()
<environment: R_GlobalEnv>
> substitute(f, environment())
f
> substitute(f, globalenv())
f
As demonstrated, when using the global environment as the second argument the functionality fails.
A further demosntration that it works correctly using a but not the global environment:
> evalq(substitute(f), a)
function(x){x^2}
> evalq(substitute(f), environment())
f
Quite puzzling.
Apparently that's indeed some weird quirk of substitute and is mentioned here:
/* do_substitute has two arguments, an expression and an
environment (optional). Symbols found in the expression are
substituted with their values as found in the environment. There is
no inheritance so only the supplied environment is searched. If no
environment is specified the environment in which substitute was
called is used. If the specified environment is R_GlobalEnv it is
converted to R_NilValue, for historical reasons. In substitute(),
R_NilValue signals that no substitution should be done, only
extraction of promise expressions. Arguments to do_substitute
should not be evaluated.
*/
And you have already found a way of circumventing it:
e = new.env()
e$fn = f
substitute(fn, e)

Resources