1

As in other functional languages, returning a function is a common case in R. for example, after training a model you'd like to return a "predictor" object, which is essentially a function, that given new data, returns predictions. There are other cases when this is useful, of course.

My question is when does the binding (e.g. evaluation) of values within the returned function occur.

As a simple example, suppose I want to have a list of three functions, each is slightly different based on a parameter whose value I set at the time of the creation of the function. Here is a simple code for this:

function.list = list()
for (i in 1:3) function.list[[i]] = function(x) x+i

So now I have three functions. Ideally, the first one returns x+1, the second computes x+2 and the third computes x+3

so I would expect:

function.list[[1]] (3) = 4
function.list[[2]] (3) = 5

etc.

Unfortunately, this doesn't happen and all the functions in the list above compute the same x+3. my question is why? why does the binding of the value of i is so late, and hence the same for all the functions in the list? How can I work around this?

EDIT: rawr's link to a similar question was insightful, and I thought it solved the problem. Here is the link: Explain a lazy evaluation quirk

however, I checked the code I gave above, with the fix suggested there, and it still doesn't work. Certainly, I miss something very basic here. can anyone tell me what is it? here is the "fixed" code (that still doesn't work)

function.list = list()
for (i in 1:3) { force(i); function.list[[i]] = function(x) x+i}

Still function.list[[1]] (3) gives 6 and not 4 as expected. I also tried the following (e.g. putting the force() inside the function)

function.list = list()
for (i in 1:3) function.list[[i]] = function(x) {force(i);x+i}

what's going on?

Community
  • 1
  • 1
amit
  • 3,332
  • 6
  • 24
  • 32
  • 1
    Here's a kludgy way: `for (i in 1:3) function.list[[i]] = eval(substitute(function(x) x+i,list(i=i)))` – Frank May 16 '15 at 14:07
  • 2
    http://stackoverflow.com/questions/16129902/explain-a-lazy-evaluation-quirk – rawr May 16 '15 at 14:13
  • As @rawr says, this is an exact duplicate. – tchakravarty May 16 '15 at 14:19
  • @rawr OK, checked the solutions suggested on the link you provided, and it still doesn't work in my case. see the edited question for the problems I encountered and the code I tried. – amit May 16 '15 at 16:29
  • @amit one problem with using for loops vs the apply family is they clutter your workspace. any variables you create (outside of the functions) including the index, i, will be left around as garbage. when the functions look for an i, they always find it, and since the last iteration was 3, i takes value 3. `lappy` like in the link doesn't have this problem `y <- lapply(1:3, function(i) function.list[[i]] = function(x) {force(i);x+i}); y[[1]](3)` again, i is not found, but `lapply` "remembers" when i is forced to evaluate. but like in the link, since v3.2 you don't need to `force` anymore – rawr May 16 '15 at 18:15

1 Answers1

0

Here's a solution with a for loop, using R 3.1:

> makeadd=function(i){force(i);function(x){x+i}}
> for (i in 1:3) { function.list[[i]] = makeadd(i)}
> rm(i) # not necessary but causes errors if we're actually using that `i`
> function.list[[1]](1)
[1] 2
> function.list[[2]](1)
[1] 3

The makeadd function creates the adding function in a context with a local i, which is why this works. It would be interesting to know if this works without the force in R 3.2. I always use the force, Luke....

Spacedman
  • 92,590
  • 12
  • 140
  • 224