0

The following simplified version of my program captures the confusion.

I am trying to create a set of functions f1, f2, ..., fK, ..., fn defined as fK(x) = print(K + x). For this, I created the function factory:

factory = function (K) {
    function (x) print(K + x)
}

And use it to create 5 functions: funcs = sapply(1:5, factory)

I call them one by one, for the same value: x = 10

callOnef = function (f, x) f(x)
sapply(funcs, callOnef, 10)

I expected the output to be (one per line) 11 12 13 14 15, but I instead got (one per line) 15 15 15 15 15 and on the 6th line, a row of five 15 's.

When I inserted a print(K) in the definition of factory, the output changed to (one per line) 11 12 13 14 15 and on the 6th line, a row of 11 12 13 14 15. (Ignoring the output of print(K) itself, that preceded the 6 lines)

This confused me a lot. I found a thread where there's a suggestion to use force.

So, I replaced print(K) with force(K):

factory = function (K) {
    force(K)
    function (x) print(K + x)
}

The output is now (one per line) 11 12 13 14 15 and on the 6th line, a row of 11 12 13 14 15.

Questions:

  1. Why does the evaluation of K (like in my case through print(K) or force(K),) change the behavior of the closure?
  2. Why the 6th line? It looks identical to the output of print(K + 10) if K was a vector equal to 1:5.
Community
  • 1
  • 1
Anant
  • 222
  • 2
  • 8
  • 2
    This is partially a duplicate of this question: http://stackoverflow.com/q/15742177/269476. The second part is due to the fact that `sapply` returns and prints (if used interactively) the output. – James Oct 13 '13 at 13:22

1 Answers1

2

This strange behavior is a consequence of R's lazy evaluation. R doesn't evaluate the parameters to a function until it needs to. Instead it creates a promise object, which consists of a expression and an environment.

You can see what is happening more clearly in this code:

> factory = function (K) {
+     function (x) {
+         print(K + x)
+     }
+ }
> funcs<-list()
> for(i in 1:5)
+     funcs[[i]]<-factory({cat("evaluating K:",i,"\n"); i})
> 

Nothing was printed out, meaning that the arguments to the factory calls have not been evaluated yet. They are still bound to the promise of evaluating {cat("evaluating K:",i,"\n"); i} in the global environment. Since i now is equal to 5, then we get this behavior:

> funcs[[1]](10)
evaluating K: 5 
[1] 15

If we change i in the global environment, it will affect the still unevaluated promises, but not the promises which have already been resolved:

> i<-4
> funcs[[2]](10)
evaluating K: 4 
[1] 14
> funcs[[1]](10)
[1] 15

The reason force changes this behavior is because force forces a promise to be evaluated on the spot, so the promise immediately becomes a value.

As for the second part of your question, the 6'th row is simply the output of sapply, which concatenates together the results of all the expressions.

mrip
  • 14,913
  • 4
  • 40
  • 58
  • Thanks for this very clear explanation! I wonder why this important consequence of lazy evaluation isn't mentioned in the [R intro](http://cran.r-project.org/doc/manuals/r-release/R-intro.html). It would be very helpful for newbies :) – Anant Oct 14 '13 at 13:05
  • 1
    @Anant Yes, the R documentation can be less than ideal sometimes. Promises and lazy evaluation are mentioned in the R language definition though: http://cran.r-project.org/doc/manuals/R-lang.html#Promise-objects – mrip Oct 14 '13 at 13:11