What is the usefulness of lexical and dynamic scopes in R?

Asked

Viewed 261 times

14

In the chapter 6 of the book Advanced R there are definitions of lexical and dynamic scopes. However, I did not understand the usefulness of knowing these concepts in r. Thus,

  • the usefulness of the lexical scope in r?
  • the usefulness of the dynamic scope in r?

The author offers several examples on these forms of scope. But, I repeat, I need to know the usefulness thereof.

This question can be considered an addendum to this here. Note that even if Sopt has questions about constructor and inheritance in other programming languages, on r some concepts may have less or more employment utility.

And this is what I want to know: utility of lexical and dynamic scopes in r.

  • 1

    Are you talking about dynamic scope or * Dynamic lookup*?

  • Dynamic scope.

1 answer

10


These concepts are very important for those who develop R packages and need to create complex functions behaviors, although for the day-to-day analysis of data is not so necessary.

First, to understand the concept of lexical scope and dynamic scope, I think the best example is the following:

y <- 100

f <- function(x) {
  y <- 2
  g(x)
}

g <- function(x) { 
  x*y
}

f(5)
[1] 500
g(5)
[1] 500

In R, the scope is lexical, that is, the functions look for the values of the variables in the same environment in which they were defined and not in the environment in which they were called. In the example above, if the scope was dynamic then y would assume the value 2 and the result of f(5) would be 10. It is important to note that if you change the value of y after the creation of the function, R will use the new value. For example:

y <- 10
f(5)
[1] 50

That is, R stores where to find the variable value and not the variable value when the function is created.

What is the use of the lexical scope? As a function always accesses variables that are in the scope in which it was defined, you can create functions of the following type:

counter <- function() {
  i <- 0
  function() {
    i <<- i + 1
    return(i)
  }
}
count <- counter()
count2 <- counter()
count()
[1] 1
count()
[1] 2
count()
[1] 3
count()
[1] 4
count2()
[1] 1
count2()
[1] 2
count()
[1] 5

On a day-to-day basis, this may not be useful, but in some rare moments you may need to create functions that have complex behaviors like this.

Another common use is to create functions like generators, an example is this one:

sampling_generator <- function(X_data, Y_data, size) {
  function() {
    rows <- sample(1:nrow(X_data), size, replace = TRUE)
    list(X_data[rows,], Y_data[rows,])
  }
}

This function returns a different random sample of X_data and Y_data each time it is called. This allows you to create very interesting abstractions in your code.

In R, it is also possible to modify these functions' scope rules. Modifying these rules can make your function simpler to use. The functions of dplyr make good use of it, for example when we write:

dplyr::mutate(mtcars, cyl = cyl * 2)

In this case, the lexical scope rule was disregarded since the function did not look for the variable cyl in the global environment, where it would have been natural and yes within the mtcars. This code also did not create a variable cyl within the global environment and yes within the mtcars.

In this case, modifying the scope rule makes the function user have to type much less which can be very useful when we are doing data analysis.

In summary, in most cases, when using functions defined by other developers we don’t need to worry about lexical or dynamic scope. When creating packages or functions that will be used by other people we can think whether we want the lexical scope or modify the scope rules to improve the functions API. We may also abuse these scope rules to create more advanced behaviors for functions.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.