Reputation: 2406
I have a differential operator that acts on two functions. To simplify the problem let's say that my operator is
A[F_,G_] := D[F,x] D[G,y]
I want to be able, if I know F, to define a differential operator AF such that AF[G] is equal to A[F,G]. The obvious way is
AF[G_] := A[F,G]
which works without any problem. But what I would really like is to arrange things so that when I call AF with different arguments G1, G2, ... the derivative D[F,x] is not re-computed every time but only once. Moreover, I would like the definition of AF to not depend on the particular form of A, since A is passed as an argument to my function.
I have read the help on Hold, HoldAll, Evaluate etc. but I cannot put these things together to get what I want. I don't even know if what I want is possible in Mathematica.
Upvotes: 4
Views: 2256
Reputation: 48687
Can you not just do:
A[F_] := With[{DF = D[F, x]}, Function[{G}, DF D[G, y]]]
That is similar to currying in a real functional programming language like F#, where you would write:
let a f =
let df = d f x
fun g -> df * d g y
Upvotes: 0
Reputation: 9901
With the problem you describe, I don't see a straightforward way of doing it. One thing you could do to recast it to make it dramatically easier would be to redefine A
so its a function of the derivatives of F
and G
. If you have
A[{dFdx_,dFdy_}, {dGdx_,dGdy_}] := dFdx*dFdy
you'll be in a very good position to calculate the derivatives of F
that you need and then define AF
in a way that's generic with respect to A
, like so:
With[{ dFdx = D[F,x], dFdy = D[F,y] },
AF[G_] := A[{dFdx, dFdy}, {D[G, x], D[G, y]}]]
You can use With
to substitute evaluated pieces into the unevaluated right-hand side of a SetDelayed form (a definition using ":=") as shown. However, if you can't make that change, things are going to get hairy, and you'll have to make some assumptions about what A
is.
If A
is a symbol with DownValues defined for it, and has a simple definition, then you can do the partial evaluation you want by using a Hold
, doing rule substitutions, and then doing a ReleaseHold
, like so:
ReleaseHold[
Hold[AF[G_] := A[F, G]] /. DownValues[A] /.
HoldPattern[D[F, var_]] :> With[{eval = D[F, var]}, eval /; True]]
The With[...]
bit in the second rule is a trick for forcing the evaluation of something matching a pattern inside a Hold
called the "Trott-Strzebonski method", which is obscure but extremely useful for tasks like this. However, going this way really limits your interface, meaning that you can't, say, pass in a pure function for A
, and with a more complicated definition this trick probably won't work either. If you can possibly manage to specify that your differential form will be a function of the actual derivatives, I strongly recommend doing so.
EDIT: I thought of a more general and robust way of doing this.
The trick then is to temporarily suppress the definition of D
(the derivative operator) using Block
, so the derivatives in the definition of A
remain unevaluated, and then use rule-replacement to substitute in the values for the derivatives of F
while wrapping everything up in a pure function to get the name substitution right, like so:
With[{fRules =
{HoldPattern[D[F, x]] :> Evaluate[D[F, x]]}},
Block[{D},
With[{fn = Function[G, Evaluate[A[F, G] /. fRules]]},
AF[G_] := fn[G]]]]
Upvotes: 4