11

Is there an easy way to combine pure functions into a single pure function? For example, say I have

f = #1^2 &;
g = #1 - 2 &;

and I want to define a new pure function h that is the difference of the two functions (as currently defined, so that h will not change if f or g are redefined). h = f - g doesn't work because it doesn't combine them into a single function. The best I've been able to come up with is

h = Evaluate[f@# - g@#] &

but this seems a bit hack-ish. Is there a more natural way to combine them?

Edit: I was looking for something where Mathematica performs its automatic simplifications, just as if we'd had f = x^2; g = x - 2; h = f - g, but for pure functions.

tparker
  • 1,856
  • 12
  • 22
  • Why not simply #1^2 + #1 - 2 & ? And see http://mathematica.stackexchange.com/questions/33112/how-combine-pure-functions-of-several-slots – David G. Stork Apr 07 '17 at 01:43
  • @DavidG.Stork Well of course if the functions are known and this short, then you can just define the combined function manually. But I want to be able to handle the case where the functions are unknown and/or extremely complicated. – tparker Apr 07 '17 at 02:03
  • h = f@# + g@# &? – wxffles Apr 07 '17 at 02:05
  • @wxffles This is a step in the right direction, but not really what I want because it leaves the functions unevaluated and sensitive to later changes in their definitions. I edited the question to incorporate your suggestion (since mine original version doesn't work for subtraction), but I was really wondering if there was a way to eliminate the Evaluate. Probably not, and now the code seems more natural, so if you post an answer I'll accept it. – tparker Apr 07 '17 at 02:15
  • 3
    Wanting h to not be affected by later changes to f and g is an important point you should put in the question. – wxffles Apr 07 '17 at 02:24
  • With f + g you can use h = Through @* (f+g), but with - the issue is that f and g are a bit deeper inside the expression tree (since f-g is really Plus[f, Times[g, -1]]). – Martin Ender Apr 07 '17 at 09:50
  • 5
  • Nearly a duplicate: (87985) – Mr.Wizard Apr 08 '17 at 06:34
  • @Mr.Wizard I think that question has a very different focus from mine and is only superficially related. – tparker Apr 08 '17 at 18:46
  • I'd say the relation is more than superficial but you'll note that I neither closed this nor suggested that others vote to do so. :-) – Mr.Wizard Apr 08 '17 at 23:36

2 Answers2

6

This is a solution for the simplest case.

Not meant to prevent evaluation (except of the components' functions bodies).

It only works with expressions with slots & kind of pure functions etc. So it won't merge named arguments or resolve attributes from Function.

mergeF[expr_] := Function @@ (Hold[expr] /. Function[body_] :> body)

  (* or Replace[Function[expr], Function[body_] :> body, {1, -1}]*)

mergeF[(f - g)/Exp[g]]

enter image description here

If don't need to care at all you can drop Hold.

Kuba
  • 136,707
  • 13
  • 279
  • 740
3

Use With:

h = With[{f = f, g = g},  f[#] - g[#] &]
Alan
  • 13,686
  • 19
  • 38
  • It will work but it is not the same as OP's h – Kuba Apr 07 '17 at 13:06
  • @Kuba I'm not sure what you mean. His use of Evaluate accomplishes nothing, but the use of With achieves what he was asking for (i.e., eliminates the appearance of f and g in the own values of h, as he requested in his comments). – Alan Apr 07 '17 at 15:40
  • 1
    I'm not sure what do you mean too :) this is what OP's h is: 2 - #1 + #1^2 & and this is what is yours: (#1^2 &)[#1] - (#1 - 2 &)[#1] &. Of course Evaluate does its job there. – Kuba Apr 07 '17 at 15:46
  • @Kuba On Evaluate: right, I see what he did. (I had thought he evaluated the function expression, not just the argument.) On the difference: does it make a difference? Hmm, I suppose Evaluate could lead to simplifications, avoiding the need to recompute them every call. So then, was using Evaluate that way a good solution after all? I thought using With was the standard answer. – Alan Apr 07 '17 at 16:34
  • I wouldn't say one way is better than another unless OP narrows the case. As you noticed your solution prevents simplifications/evaluation, which is reasonable choice. – Kuba Apr 07 '17 at 16:36
  • I edited the question to clarify that I want Mathematica to perform its automatic simplifications. – tparker Apr 08 '17 at 02:20