I have a problem where, after som expensive calculations, an anonymous function is created. The anonymous function needs to return a tuple of the results depending on the users input. Here is an example of what I wish to achieve.
function run(funs::Array{Symbol,1})
#f1,f2,f3 are expensive and only available at run time
f1 = x->minimum(x)
f2 = x->maximum(x)
f3 = x->sum(x)
return function (x)
...
end
end
To me it seems like a problem which could (should?) be solved by metaprogramming; however, my attempts have been hacky at best. Iβm sure thereβs an elegant Julian way of doing it!
julia> function foo(funcs)
return x -> [f(x) for f in funcs]
end
foo (generic function with 2 methods)
julia> foo(funcs...) = foo(funcs)
foo (generic function with 2 methods)
julia> g = foo(f1, f2)
#9 (generic function with 1 method)
julia> g([3, 4, 5])
2-element Array{Int64,1}:
5
12
Do you have an idea of how I could get the interface to work? The application where Iβm using this is nested in an expensive function which generates f1,f2,f3 in the example and both the number of functions and their order can vary based on the user input.
function run(funs::Array{Symbol,1})
#f1,f2,f3 are expensive and only available at run time
f1 = x->minimum(x)
f2 = x->maximum(x)
f3 = x->sum(x)
return function (x)
...
end
end
The following seems to work pretty well for the problem as youβve posed it:
julia> function run(names::Vector{Symbol})
library = Dict(
:f1 => x -> minimum(x),
:f2 => x -> maximum(x),
:f3 => x -> sum(x)
)
functions_to_call = Tuple([library[s] for s in names])
return function (x)
call.(functions_to_call, Ref(x))
end
end
run (generic function with 1 method)
julia> call(f, x) = f(x)
call (generic function with 1 method)
julia> f = run([:f1, :f2])
#38 (generic function with 1 method)
julia> f([1,2,3])
(1, 3)
Some notes:
Iβm assembling a Dict mapping names to functions, rather than trying to look them up by the names of the variables theyβre bound to. I wouldnβt recommend trying to access things inside some other function by their variable names: variable names donβt really exist in the compiled code, so looking things up by variable name isnβt a great idea.
I construct a Tuple of functions to call instead of just a list so that Julia can correctly infer the number of outputs of the resulting function (a tupleβs length is part of its type, which is not true for an Array). That means that Julia can correctly infer the output type of f() in the above example: