4
$\begingroup$

I am trying to create a list of functions in a loop, using a list of parameters as input to the functions. However, after assigning the each of the functions to the array, when evaluating the functions only the last value of the parameter is being used.

Perhaps a simple example explains this best

a = Array[0, 2];
For[i = 1, i <= 2, ++i,
 a[[i]] = Function[{x}, i + x];
]

Giving the result

a={Function[{x}, i + x], Function[{x}, i + x]}

Now if I use $x=0$ (via the Through[] function), I would expect to have the result $\{1,2\}$ because $i=1$ for the first element and $i=2$ for the second element. However, the actual result I get is $\{3,3\}$. This occurs because when I evaluate the statement the current value of $i$, being $i=3$ causing the For[] loop to break, is used.

Question: How do I get the functions to use the value of $i$ they were created with, instead of the current value.

I know there is something similar to this in JavaScript, but can't remember the correct term for it.

$\endgroup$
7
$\begingroup$

Short answer is that this will work as you expect:

 a = Array[0, 2];
    For[i = 1, i <= 2, ++i,
      With[{i = i}, a[[i]] = Function[{x}, i + x]];]

The reason why things didn't work out as you expect is that Mathematica is very different from other languages. Functions do not - as you might know from other languages - do some automatic conservation of scope at the time they are generated (you probably were looking for the term "closure"). That mechanism can in Mathematica be achieved by different means but is not automatic.

In Mathematica what you have to understand is the evaluation order, and I think the explanation in the documentation is a good starting point, when you know the terms "evaluation order" and "nonstandard evaluation" you will also find a lot of useful questions and answers on this site.

One more note is that you should not get into the habit of using For in Mathematica, it is never a good solution, see e.g. this question and answers for more details. Here is how I would solve your problem:

a = Table[With[{i = i}, Function[i + #]], {i, 2}]
Through[a[0]]

or even, but that is admittedly a bit tricky:

a = Function[i, # + i &] /@ Range[2]
| improve this answer | |
$\endgroup$

Not the answer you're looking for? Browse other questions tagged or ask your own question.