Creating a pure function that does operations with pure functions

Haven't found a duplicate nor it is rtfm question so I will leave this cw answer:

c = a[#] + b[#]&

which should be clear but feel free to ask otherwise.


For simple expressions like a sum, there is Through. The following kind of use is shown in the docs:

a[3] + b[3]
Through[(a + b)[3]]
(*
  18
  18
*)

It works for simple homogeneous expressions like a + b or a * b, in which all the elements of level 1 are functions. To get a function as a result instead of a value, one can use # and & instead of 3 as shown below. One might use Evaluate to evaluate the body. Beware that symbolic parameters would have their values substituted, if any, when Evaluate is used. One can see from the output below that the unevaluated construction still depends on the definitions of a and b, and in the evaluated construction, we have a definite function that does not depend on any external values or definitions. One should consider which is most appropriate in a given use case.

c = Through[(a + b)[#]] &
c = Evaluate@Through[(a + b)[#]] &
(*
  Through[(a + b)[#1]] &
  6 + #1 + #1^2 &
*)

Sometimes it happens that a more complicated combination of functions is desired. Let's say the expression has been generated programmatically, either in the symbolic form 1 + 5 x + y^2 or more awkwardly in the form 1 + 5 a + b^2, with the Function expressions substituted

1 + 5 a + b^2
(*  1 + 5 (#1 + 3 &) + (#1^2 + 3 &)^2  *)

Then ReplaceAll (/.) will be your friend. Again the same advantages and disadvantages of Evaluate should be considered.

1 + 5 a + b^2 /. {a -> a[3], b -> b[3]}
(*  175  *)

c = 1 + 5 a + b^2 /. {a -> a[#], b -> b[#]} &
c = Evaluate[1 + 5 a + b^2 /. {a -> a[#], b -> b[#]}] &
(*
  1 + 5 a + b^2 /. {a -> a[#1], b -> b[#1]} &
  1 + 5 (3 + #1) + (3 + #1^2)^2 &
*)

Here's a simple function that operates somewhat like Through on a functional expression (expr)[x]. A second argument specifies the functions to be replaced in the operation. They can be rules that substitute a function for a symbol. if it is Automatic, the expressions in Variables[expr] are treated as functions. (I was surprised Automatic works for expressions in terms of the OP's a and b, which are pure functions.)

plugin[expr_[x___], fns_: Automatic] := 
  expr /. Replace[
    Flatten[{fns} /. Automatic :> Variables[expr]], (* construct replacements:          *)
    {HoldPattern[f_ -> g_] :> f :> g[x],            (*   rule for f:  f :> plug into g  *)
     f_ :> f :> f[x]},                              (*   function f:  f :> plug into f  *)
    1];

Examples:

plugin[(1 + 5 a + b^2)[3]]                                (* Automatic substitution *)
(*  175  *)

Evaluate@plugin[(1 + 5 a + b^2)[#]] &                     (* Automatic substitution *)
(*  1 + 5 (3 + #1) + (3 + #1^2)^2 &  *)

Evaluate@plugin[(1 + 5 a + b^2)[#], {a, b}] &             (* Specified functions *)
(*  1 + 5 (3 + #1) + (3 + #1^2)^2 &  *)

Evaluate@plugin[(1 + 5 x + y^2)[#], {x -> a, y -> b}] &   (* Substitution via rules *)
(*  1 + 5 (3 + #1) + (3 + #1^2)^2 &  *)

Simplify@plugin[(x^2 + y^2)[t], {x -> Cos, y -> Sin}]
(*  1   *)

plugin[(x^2 - 3 y^2 + z)[u, v]]
(*  x[u, v]^2 - 3 y[u, v]^2 + z[u, v]  *)