Function operators and environments

Viewed 37

Alright stackies,

I've been reading Advanced R and have really found it helpful. I'm at a spot where I really don't understand R's behavior in the example:

dot_every <- function(n, f) {
  i <- 1
  function(...) {
    if (i %% n == 0) cat(".")
    i <<- i + 1
    f(...)
  }
}

So the idea here is that we are to display a period every nth iteration of the function. What I don't understand is how the value of i is being maintained through multiple calls of dot_every in a functional. I understand that <<- moves up through environments searching for something named i and then replaces with i+1. I would have thought that something like this:

x <- lapply(1:20, dot_every(10, runif))

would garbage collect that i for each iteration in lapply and thus never increment it. My intuition is that it would work like this:

for(i in 1:20){
  dot_every(10, runif)(i)
}

Which does seem to be calling dot_every, garbage collecting i, and thus not displaying anything. What's different about using the functional than the for loop in this case?

Thanks for your help!

1 Answers

In the first case (with the lapply) you are calling dot_every() only once, and then using the resulting function on every element in 1:20. In the second case, you are calling dot_every() in every pass through the loop, and then using the resulting function just once. To see this, insert the line:

cat("!")

as the first line in the definition of dot_every(). Then:

> x <- lapply(1:20, dot_every(10, runif))
!..

but

> for(i in 1:20) dot_every(10,runif)(i)
!!!!!!!!!!!!!!!!!!!!
Related