tags:

views:

97

answers:

3

I would like to create a vector of functions using a two agruments function 'func', for instance this one:

func = function(number, coefficient) {  
    return(coefficient*number)  
}

here is how I create the vector of functions:

vector_of_functions = NULL  
for (i in 1:4) {  
vector_of_functions = c(vector_of_functions,
    function(number) func(number=number, coefficient=i))  
}

My issue is that all functions that compose my vector are the same, even if they have been created using different i through the loop. It seams that they are evaluated using the last value of i (which is here a global variable).

Anybody has an idea?

Thanks

+2  A: 

This can be solved using an eval-parse construct, although I strongly advice you not to use this construct. It often causes more problems than anything else. But I couldn't get a decent do.call way of doing it.

vector_of_functions = NULL
for (i in 1:4) {
vector_of_functions = c(vector_of_functions,
  eval(parse(text=paste("function(number) func(number=number, coefficient=",i,")"))))
}

Reason is as Aaron explained: everything within the function definition is taken as is until the function evaluation.

Small remark: this is especially a list of functions, and not a vector. It's impossible to have a vector of type "function". It's also absolutely useless, as you have to select the function using the index [[]] before you can use it. Then I'd just add the argument instead of defining a function for every possible value of one of the arguments.

So what you want to achieve is unclear, but if you want to apply func with different coefficients, I wonder why you don't simply do:

> x <- c(10,20,30)
> sapply(1:4,function(y)func(number=x,coefficient=y))
     [,1] [,2] [,3] [,4]
[1,]   10   20   30   40
[2,]   20   40   60   80
[3,]   30   60   90  120

A variation on the theme by Marek (avoiding the parsing):

vector_of_functions = NULL
for (i in 1:4) {
vector_of_functions = c(vector_of_functions,
  eval(substitute(function(number) func(number=number, coefficient=i),list(i=i))))
}

The 1L etc. you get, just indicate they're exact integers (that take less memory space).

Joris Meys
Instead of `parse(text(` thing better use `substitute`: `eval(substitute(function(number) func(number=number, coefficient=i),list(i=i)))`
Marek
+2  A: 

You can "attach" the value of i to each function by redefining i in its own local environment (conveniently created by the function, local in R). The resulting function with data "attached" is called a 'closure'.

> vector_of_functions = NULL  
> for (i in 1:4) {  
+ vector_of_functions = c(vector_of_functions,
+     local({i <- i;function(number) func(number=number, coefficient=i)}))
+ }
> vector_of_functions[[1]](1)
[1] 1
> vector_of_functions[[2]](1)
[1] 2
> vector_of_functions[[3]](1)
[1] 3
> vector_of_functions[[4]](1)
[1] 4
Stephen
Thanks Stephen, that's a great think I learn here.
Fred
A: 

The problem is due to lazy evaluation, the 'i' variable is not being evaluted at each step, so when you call the function it uses the last value. The force function was created to force the evaluation in cases like this (there is an example on the help page for ?force that is very similar to your question).

Greg Snow