Suppose we're given the expression f*g+h
, where f,g,h
are all pure functions. How can we evaluate this expression on some x
? If there were only one operation, say f+g
, we could simply use Through[(f+g)[x]]
, but Through
only deals with one operation, as far as I can see. How is this done?
3 Answers
Edit:
Mr.Wizard helped to refine my old function to:
SetAttributes[Through2, HoldFirst]
Through2[head_[args___]] := Replace[head, s : _Function | _Symbol :> s[args], -1]
This locates the most nested functions and symbols and evaluates their value for the parameter arguments.
Below is my older, less robust function:
SetAttributes[Through2, HoldFirst]
Through2[expr_] :=
With[{head = Head@expr, arg = First@expr},
With[{funcs = Cases[head, _Function | _Symbol, -1]},
head /. Thread[funcs -> Through[funcs[arg]]]]]
Through2[(f*g + h)[x]]
(* f[x] g[x] + h[x] *)
Through2[(f*g + (h*Minus)^2)[x]]
(* f[x] g[x] + x^2 h[x]^2 *)
Through2[{Re, Im + Re}[x]]
(* {Re[x], Im[x] + Re[x]} *)
-
$\begingroup$ Interesting interpretation. +1 I still wonder what the OP actually wants however. $\endgroup$ Commented Jul 4, 2013 at 7:00
-
Perhaps you want something like this?
apply = (# /. s_Symbol /; Context[s] =!= "System`" :> s[##2]) &;
apply[f*g + h, x]
f[x] g[x] + h[x]
This is a limited implementation but it can be extended if this is in fact the kind of operation you desire. The idea is to recognize any Symbol not belonging to the System`
context as a function to apply to x
. Alternatively one could apply only symbols in the Global`
context using Context[s] === "Global`"
.
-
$\begingroup$ Yes, I'd say that our functions do the same thing (with yours being more elegant and direct). In hindsight,
Cases
and thenReplaceAll
does seem a bit redundant - and dangerous, too, if one of the pure functions is used on a higher level in the expression. Your solution will be more robust. $\endgroup$– VF1Commented Jul 4, 2013 at 7:13 -
$\begingroup$ @VF1 Thanks for the check. If you'd like to put this in your answer instead that's fine with me; it was your idea to look at the levelspec. $\endgroup$ Commented Jul 4, 2013 at 7:22
-
-
$\begingroup$ @VF1 It just occurred to me that my
{-1}
code is broken forFunction
as that will not be found at level{-1}
; Please use theHeads -> False
code, assuming that isn't broken. $\endgroup$ Commented Jul 4, 2013 at 7:26 -
$\begingroup$ Is there a difference between Yours
apply
and @VF1 'sThrough2
exept that the latter works for 1 argument only (after edit it works for many) and Yours can not handleMinus
and otherSystem
context functions? $\endgroup$– KubaCommented Jul 4, 2013 at 7:29
For example...
f=#&;
g=2#^2&;
h=-Sqrt[#]&;
Using substitution rule...
f*g+h /. z:(f|g|h)->z[3]
Gives...
54-Sqrt[3]
x
? Your example isPlus[Times[f,g],h]
, so the functions you want applied to x areLevel[f*g + h, {-1}]
? $\endgroup$Apply[(f[##] g[##] + h[##]) &, {arguments}]
, crude version of what Mr. Wizard have showed. $\endgroup$