Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing functions in R, keeping scoping in mind

Tags:

scope

r

I often write functions that need to see other objects in my environment. For example:

> a <- 3 > b <- 3 > x <- 1:5 > fn1 <- function(x,a,b) a+b+x > fn2 <- function(x) a+b+x > fn1(x,a,b) [1]  7  8  9 10 11 > fn2(x) [1]  7  8  9 10 11 

As expected, both these functions are identical because fn2 can "see" a and b when it executes. But whenever I start to take advantage of this, within about 30 minutes I end up calling the function without one of the necessary variables (e.g. a or b). If I don't take advantage of this, then I feel like I am passing around objects unnecessarily.

Is it better to be explicit about what a function requires? Or should this be taken care of via inline comments or other documentation of the function? Is there a better way?

like image 906
Christopher DuBois Avatar asked Jul 23 '09 03:07

Christopher DuBois


People also ask

What is scoping rule in R?

The scoping rules of the language define how value is assigned to free variables. R uses lexical scoping, which says the value for z is searched for in the environment where the function was defined. Note: Lexical scoping is also referred to as statical scoping.

What is a scoping function?

What are scope functions? In Kotlin, scope functions are used to execute a block of code within the scope of an object. Generally, you can use scope functions to wrap a variable or a set of logic and return an object literal as your result. Therefore, we can access these objects without their names.

Which scoping type free variables are resolved from previous function calls?

In R, the free variable bindings are resolve by first looking in the environment in which the function was created. This is called Lexical Scoping.

What are the components of R functions?

To understand functions in R you need to internalise two important ideas: Functions can be broken down into three components: arguments, body, and environment.


1 Answers

If I know that I'm going to need a function parametrized by some values and called repeatedly, I avoid globals by using a closure:

make.fn2 <- function(a, b) {     fn2 <- function(x) {         return( x + a + b )     }     return( fn2 ) }  a <- 2; b <- 3 fn2.1 <- make.fn2(a, b) fn2.1(3)    # 8 fn2.1(4)    # 9  a <- 4 fn2.2 <- make.fn2(a, b) fn2.2(3)    # 10 fn2.1(3)    # 8 

This neatly avoids referencing global variables, instead using the enclosing environment of the function for a and b. Modification of globals a and b doesn't lead to unintended side effects when fn2 instances are called.

like image 84
ars Avatar answered Oct 06 '22 14:10

ars