Reputation: 14614
I want to generate an array of functions programmatically, with a loop so that each successive function depends on the previous.
For example in pseudo-code:
f_array = [f1, f2, f3]
with:
f1(x) = x
f2(x) = 3 * f1(x)
f3(x) = 3 * f2(x)
so that I could call:
f_array[3](x)
and get the result of f3(x)
Here is what I have tried:
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = fill(f, N)
# now we update each function
for i in 2:N
f_array[i] = (f(x)= 3 * f_array[i-1](x))
end
I get an error:
ERROR: MethodError: Cannot
convert
an object of type getfield(Main, Symbol("#f#15")){Int64} to an object of type typeof(f)
I cannot find a solution at the moment. Any help would be appreciated.
Upvotes: 1
Views: 1645
Reputation: 20980
I'd write Yegor's answer as
f_array = Function[identity]
for i in 2:3
push!(f_array, x -> 3f_array[i-1](x))
end
But more importantly, this is a well known pattern: iterated function application. And it is already implemented, not in Base, but for example in IterTools.jl, by which you should be able to write:
f_array(start, N) = collect(Iterators.take(iterated(x -> 3x, start), N))
(I didn't test this, though.)
Upvotes: 1
Reputation: 14614
In the mean time, I also found a way using metaprogramming. I post this here as it could be useful for others:
f1(x) = x
for i in 2:N
prog = "f$i(x) = 3 * f$(i-1)(x)"
exp = Meta.parse(prog)
eval(exp)
end
f3(2)
# 18
Upvotes: 1
Reputation: 6152
When you use fill
with f
it sets expected type for the elements of f_array
to f
, in the code below I am switching to abstract type to make it possible to have any function in the array
# create simple function just to initialize
f(x)=x
# initialize array of functions
N = 3
f_array = Array{Function}(undef, N);
f_array[1] = f;
# now we update each function
for i in 2:N
f_array[i] = x -> 3 * f_array[i-1](x)
end
print(f_array[3](2))
which produces a value of 18
Upvotes: 2