As a part of a project I'm working on I found myself wanting to solve a
problem, which in English would be phrased:
"Given a vector of parameterized univariate functions [f1(x1, P1), f2(x2,
P2), f3(x3, P3), ...] with argument xj and parameters Pj, along with a
vector of parameters [P1, P2, P3...], return a multivariate function
g(x1,x2,x3, ...) which is the product of the parameterized input functions:
f1(x1, P1)*f2(x2, P2)*f3(x3, P3)*..."
I decided, after some investigation, that this might be best solved by some
metaprogramming. I am not at all familiar with metaprogramming, so I ended
up spending a full day trying to make this function... (don't judge me).
But it works! So I'll post it as a slightly more than trivial example.
function prodFun(P::Vector, f::Vector{Function})
ex = Expr(:call,Expr(:ref,:($f),1),:(X[1]),:($(P[1])))
for k=2:length(f)
exnew = Expr(:call,Expr(:ref,:($f),:($k)),:(X[$k]),:($(P[k])))
ex = Expr(:call,:*,ex,exnew)
end
return eval(Expr(:(=),Expr(:call,:g,:x),ex))
end
Here's an example of it in action:
>P = {[1; 2]; [3; 4]; [5; 6]; [7; 8]}
>f(x,P) = P[1]*exp(x)/sin(P[2])
>g = prodFun(P, [f; f; f])
>g([1; 1; 1])
>>1567.0
>f(1,P[1])*f(1,P[2])*f(1,P[3])
>>1567.0
So, it works in this (and some other) test cases.
Getting to this point required a lot of fiddling around, mainly with the
dump() function. Along the journey, because I didn't really know what I
was doing, I thought maybe a macro was what I wanted. I could never get it
to work like I wanted though. I think the reason was because it required
the inputs to be expressions, but I'm not super confident. If that's the
case, though, what's the point of macros? You can make a function that
accepts expression arguments and can return an expression too, but of
course you don't have to be limited like that. Is there an under-the-hood
difference between a macro and a function that operates on expressions?