Reading global variables - r

All I can find is how to write to global variables, but not how to read them.
Example of incorrect code:
v = 0;
test <- function(v) {
v ->> global_v;
v <<- global_v + v;
}
test(1);
print(v);
This yields 2 because v ->> global_v treats v as the local variable v which is equal to 1. What can I replace that line with for global_v to get the 0 from the global v?
I'm asking of course about solutions different to "use different variable names".

You can use with(globalenv(), v) to evaluate v in the global environment rather than the function. with constructs an environment from its first argument, and evaluates the subsequent arguments in that environment. globalenv() returns the global environment. Putting those together, your function would become this:
test <- function(v) {
v <<- with(globalenv(), v) + v;
}

Related

Target multiple variables for a function within a custom function

I would like to build a function which runs a chi square test if calc=TRUE. The problem appears to be targeting the variables used within the wtd.chi.sq function.
Thank you very much in advance.
library(weights); library(sjstats)
testfunction <- function(dta, x, y, calc=TRUE, annotate=note){
if(isTRUE(calc)){
testresult<-wtd.chi.sq(dta[[x]], dta[[y]])
return(testresult["p.value"])
}
else {
annotate <- paste0(note, "... and no calc necessary")
}
return(annotate)
}
testfunction(dta=df, x=f1, y=s12x, calc=TRUE, annotate=note)
Error in tbl_subset2(x, j = i, j_arg = substitute(i)) :
object 'f1' not found

How do I create a function that takes a function as input and returns this function modified but with same input arguments?

Let for example function g be defined by g(x):=x+1.
I want to programm a function f which can take a arbitrary function h(a_1,...,a_n) (a_1,...,a_n being the arguments) and returns the function g(h). So that
f(h)(a_1=1,...,a_n=n) works and returns the same as g(h(a_1=1,...,a_n=n)).
So we need something like
f <- (h){
- get the arguments of h and put them in a list/vector arg(I found functions that do that)
- return a function ´f(h)´ that has the elements of arg as arguments. (I am not sure how to do that)
}
I'm not sure I understand your question since what you wrote seems ok but is that what you are looking for?
somelistorvector <- list(a = 1, b = 2)
fct <- function(arg){
arg[[1]] + arg[[2]] # arg[["a"]] + arg[["b"]] could also work
}
fct(somelistorvector)
[1] 3
Also are the arguments always going to be a and b or element 1 and 2 ?

Scoping without global variables in R

I seem to be deeply confused about what constitutes good practice in R. Suppose that I have the following R code:
f<-function()
{
g<-function(s)
{
b<-b+1
s<-s+5
}
b<-10
g(2)
return(b)
}
In any typical language, this will always return b=10 and to the best of my awareness, the typical way to get f to recognise that g is modifying b would be to use global variables. However, as best as I can tell, it seems to be common practice in R to avoid global variables wherever possible. This leads me to ask, how am I supposed to modify f so that it outputs b=11 without making any use of global variables? I seem to either have a very deep misunderstanding or to be ignorant of a very important idea.
There are three forms of the assignment operator in R: <-, =, and <<-. The third form, <<-, assigns the value to an object in the parent of the current environment.
If you use this form in the g() function, it increments the value of b within the f() function by 1.
f<-function()
{
g<-function(s)
{
# use <<- form instead of <-
b<<-b+1
s<-s+5
}
b<-10
g(2)
return(b)
}
...and the output:
> f<-function()
+ {
+ g<-function(s)
+ {
+ b<<-b+1
+ s<-s+5
+ }
+ b<-10
+ g(2)
+ return(b)
+ }
> f()
[1] 11
>

Why does this happen when a user-defined R function does not return a value?

In the function shown below, there is no return. However, after executing it, I can confirm that the value entered d normally.
There is no return. Any suggestions in this regard will be appreciated.
Code
#installed plotly, dplyr
accumulate_by <- function(dat, var) {
var <- lazyeval::f_eval(var, dat)
lvls <- plotly:::getLevels(var)
dats <- lapply(seq_along(lvls), function(x) {
cbind(dat[var %in% lvls[seq(1, x)], ], frame = lvls[[x]])
})
dplyr::bind_rows(dats)
}
d <- txhousing %>%
filter(year > 2005, city %in% c("Abilene", "Bay Area")) %>%
accumulate_by(~date)
In the function, the last assignment is creating 'dats' which is returned with bind_rows(dats) We don't need an explicit return statement. Suppose, if there are two objects to be returned, we can place it in a list
In some languages like python, for memory efficiency, generators are used which will yield instead of creating the whole output in memory i.e. Consider two functions in python
def get_square(n):
result = []
for x in range(n):
result.append(x**2)
return result
When we run it
get_square(4)
#[0, 1, 4, 9]
The same function can be written as a generator. Instead of returning anything,
def get_square(n):
for x in range(n):
yield(x**2)
Running the function
get_square(4)
#<generator object get_square at 0x0000015240C2F9E8>
By casting with list, we get the same output
list(get_square(4))
#[0, 1, 4, 9]
There is always a return :) You just don't have to be explicit about it.
All R expressions return something. Including control structures and user-defined functions. (Control-structures are just functions, by the way, so you can just remember that everything is a value or a function call, and everything evaluates to a value).
For functions, the return value is the last expression evaluated in the execution of the function. So, for
f <- function(x) 2 + x
when you call f(3) you will invoke the function + with two parameters, 2 and x. These evaluate to 2 and 3, respectively, so `+`(2, 3) evaluates to 5, and that is the result of f(3).
When you call the return function -- and remember, this is a function -- you just leave the control-flow of a function early. So,
f <- function(x) {
if (x < 0) return(0)
x + 2
}
works as follows: When you call f, it will call the if function to figure out what to do in the first statement. The if function will evaluate x < 0 (which means calling the function < with parameters x and 0). If x < 0 is true, if will evaluate return(0). If it is false, it will evaluate its else part (which, because if has a special syntax when it comes to functions, isn't shown, but is NULL). If x < 0 is not true, f will evaluate x + 2 and return that. If x < 0 is true, however, the if function will evaluate return(0). This is a call to the function return, with parameter 0, and that call will terminate the execution of f and make the result 0.
Be careful with return. It is a function so
f <- function(x) {
if (x < 0) return;
x + 2
}
is perfectly valid R code, but it will not return when x < 0. The if call will just evaluate to the function return but not call it.
The return function is also a little special in that it can return from the parent call of control structures. Strictly speaking, return isn't evaluated in the frame of f in the examples above, but from inside the if calls. It just handles this special so it can return from f.
With non-standard evaluation this isn't always the case.
With this function
f <- function(df) {
with(df, if (any(x < 0)) return("foo") else return("bar"))
"baz"
}
you might think that
f(data.frame(x = rnorm(10)))
should return either "foo" or "bar". After all, we return in either case in the if statement. However, the if statement is evaluated inside with and it doesn't work that way. The function will return baz.
For non-local returns like that, you need to use callCC, and then it gets more technical (as if this wasn't technical enough).
If you can, try to avoid return completely and rely on functions returning the last expression they evaluate.
Update
Just to follow up on the comment below about loops. When you call a loop, you will most likely call one of the built-in primitive functions. And, yes, they return NULL. But you can write your own, and they will follow the rule that they return the last expression they evaluate. You can, for example, implement for in terms of while like this:
`for` <- function(itr_var, seq, body) {
itr_var <- as.character(substitute(itr_var))
body <- substitute(body)
e <- parent.frame()
j <- 1
while (j < length(seq)) {
assign(x = itr_var, value = seq[[j]], envir = e)
eval(body, envir = e)
j <- j + 1
}
"foo"
}
This function, will definitely return "foo", so this
for(i in 1:5) { print(i) }
evalutes to "foo". If you want it to return NULL, you have to be explicit about it (or just let the return value be the result of the while loop -- if that is the primitive while it returns NULL).
The point I want to make is that functions return the last expression they evaluate has to do with how the functions are defined, not how you call them. The loops use non-standard evaluation, so the last expression in the loop body you provide them might be the last value they evaluate and might not. For the primitive loops, it is not.
Except for their special syntax, there is nothing magical about loops. They follow the rules all functions follow. With non-standard evaluation it can get a bit tricky to work out from a function call what the last expression they will evaluate might be, because the function body looks like it is what the function evaluates. It is, to a degree, if the function is sensible, but the loop body is not the function body. It is a parameter. If it wasn't for the special syntax, and you had to provide loop bodies as normal parameters, there might be less confusion.

R - Define a object in a function which is inside another function

I have one function inside another like this:
func2 <- function(x=1) {ko+x+1}
func3= function(l=1){
ko=2
func2(2)+l
}
func3(1)
it shows error: Error in func2(2) : object 'ko' not found. Basically I want to use object ko in func2 which will not be define until func3 is called. Is there any fix for this?
Yes, it can be fixed:
func2 <- function(x=1) {ko+x+1}
func3= function(l=1){
ko=2
assign("ko", ko, environment(func2))
res <- func2(2)+l
rm("ko", envir = environment(func2))
res
}
func3(1)
#[1] 6
As you see this is pretty complicated. That's often a sign that you are not following good practice. Good practice would be to pass ko as a parameter:
func2 <- function(x=1, ko) {ko+x+1}
func3= function(l=1){
ko=2
func2(2, ko)+l
}
func3(1)
#[1] 6
You don't really have one function "inside" the other currently (you are just calling a function within a different function). If you did move the one function inside the other function, then this would work
func3 <- function(l=1) {
func2 <- function(x=1) {ko+x+1}
ko <- 2
func2(2)+l
}
func3(1)
Functions retain information about the environment in which they were defined. This is called "lexical scoping" and it's how R operates.
But in general I agree with #Roland that it's better to write functions that have explicit arguments.
This is a good case for learning about closures and using a factory.
func3_factory <- function (y) {
ko <- y
func2 <- function (x = 1) { ko + x + 1 }
function (l = 1) { func2(2) + l }
}
ko <- 1
func3_ko_1 <- func3_factory(ko)
ko <- 7
func3_ko_7 <- func3_factory(ko)
# each function stores its own value for ko
func3_ko_1(1) # 5
func3_ko_7(1) # 11
# changing ko in the global scope doesn't affect the internal ko values in the closures
ko <- 100
func3_ko_1(1) # 5
func3_ko_7(1) # 11
When func3_factory returns a function, that new function is coupled with the environment in which it was created, which in this case includes a variable named ko which keeps whatever value was passed into the factory and a function named func2 which can also access that fixed value for ko. This combindation of a function and the environemnt it was defined in is called a closure. Anything that happens inside the returned function can access these values, and they stay the same even if that ko variable is changed outside the closure.

Resources