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?
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 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.
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.
To understand functions in R you need to internalise two important ideas: Functions can be broken down into three components: arguments, body, and environment.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With