Alternative to using global variables in functions?

Often times I find myself using unevaluated variables (i.e. they show up blue) as dummy variables in whatever I'm returning such that I can evaluate them as needed later on.

A simple example is as follows. Consider we have a function that returns a collection of monomials with 'x' as the independent variable.

getFns[n_] := Array[x^# &, n];


In this function, 'x' is simply a dummy (global) variable. Then suppose we have a function that returns a list of values corresponding to the list of monomials evaluated at specified coordinates:

useFns[fns_, coords_] := Array[fns[[#]] /. x -> coords &, Length[fns]];


Here is some sample input:

myFns = getFns; (* {x, x^2, x^3} *)
myCoords = {1, 2, 3, 4};
useFns[myFns, myCoords]


which returns (as expected):

{{1, 2, 3, 4}, {1, 4, 9, 16}, {1, 8, 27, 64}}


The problem with this approach is that if the initial dummy variable is changed, it needs to be changed each time the list of functions is evaluated at specific points which can be tedious. Is there a better way to implement this?

• I don't really understand the question (your last paragraph). What do you mean by "the initial dummy variable is changed"? If you need to avoid x getting a value accidentally, you can use \[FormalX], typed as ESC \$x ESC, which is Protected, so it's guaranteed not to have a value. – Szabolcs Apr 4 '13 at 1:49
• If the question is about how to ensure that the same variable is used in both getFns and useFns, you can pass it to these functions: getFns[n] would become getFns[n,x], etc. – Szabolcs Apr 4 '13 at 1:52
• @Szabolcs The solution I have been using is to do exactly that...pass the variables to the functions that way its only defined once at the top of my code. See my approach below. – Matthew Apr 4 '13 at 2:20
• For at least your simple example, there is Rest[LinearAlgebraVandermondeMatrix[Range]] – J. M. is away Apr 4 '13 at 2:28
• Outer[] might also be useful here: Outer[#1 @ #2 &, Table[(Evaluate[#^k]) &, {k, 3}], Range] – J. M. is away Apr 4 '13 at 2:31

One of the simplest changes to your code is to use a Formal Symbol in place of x which protects it from an unwanted global assignment. You can also simplify the code somewhat.
(The \[FormalX] symbol looks much better in the FrontEnd than it does here.)

In my examples I will use primes rather than the natural numbers simply to distinguish the output.

getFns[n_] := Array[\[FormalX]^# &, n]

useFns[fns_, coords_] := (# /. \[FormalX] -> coords) & /@ fns;

useFns[getFns, Prime ~Array~ 4]

{{2, 3, 5, 7}, {4, 9, 25, 49}, {8, 27, 125, 343}}


You can also create actual functions, which appears to be your intent given the name getFns, and use them like this:

ClearAll[getFns, useFns]

getFns[n_] := Array[Function[x, #^x &], n]

useFns[fns_, coords_] := #@coords & /@ fns;

useFns[getFns, Prime ~Array~ 4]

{{2, 3, 5, 7}, {4, 9, 25, 49}, {8, 27, 125, 343}}


You could also use Through:

getFns[Prime ~Array~ 4] // Through

{{2, 3, 5, 7}, {4, 9, 25, 49}, {8, 27, 125, 343}}


For this particular application it would be simpler to create a single Function:

oneFn[n_] := Evaluate[#^Range[n]] &

oneFn[Prime ~Array~ 4]

{{2, 3, 5, 7}, {4, 9, 25, 49}, {8, 27, 125, 343}}

• Thanks! A lot of useful examples here for now and in the future. – Matthew Apr 4 '13 at 14:07
• @Matthew You're welcome, and I'm glad I could help. Thanks for the Accept. – Mr.Wizard Apr 4 '13 at 23:48

I'm not sure this is what you are looking for, but if you take a slightly different approach to defining your sequence of pure functions, you can get them to evaluate over a data set by giving them the Listable, property.

data = Range;
makeFuns[n_] := Table[With[{i = i}, Function[x, x^i, Listable]], {i, n}]
Through[makeFuns[Length@data][data]]


{{1, 2, 3, 4}, {1, 4, 9, 16}, {1, 8, 27, 64}, {1, 16, 81, 256}}

The idea here is to eliminate any need for an explicit reference to any dummy variable. This approach works for the example you present. Perhaps it will work for you in more general situations.

• That is a very similar approach to what I just discovered. I have posted my approach below...perhaps it will be useful. – Matthew Apr 4 '13 at 2:17

I basically return a list of functions.

getFns[n_] := Array[Function[{x, y}, x^# + y^(# - 1)] &, n];


And then use the Apply (@@) function to evaluate appropriately.

useFns[fns_, coords_] := Array[fns[[#]] @@ coords &, Length[fns]];
`

This gives the correct output.