# How to distribute a generic function of two arguments (without evaluating the arguments)

I guess there is an easy way to do this, but I can't seem to figure it out. What I would like to do is to distribute a generic (i.e. without specifying what this function really does) binary function. So

f[a,b+c]


should be mapped to

f[a,b] + f[a,c]


And this must happen prior to any simplification or evaluation of the b+c term.

-

This is normally accomplished with Distribute and Unevaluated:

{a, b, c} = {1, 2, 3};

Distribute[ Unevaluated @ f[a, b + c] ]

f[1, 2] + f[1, 3]


This can be rolled into a function if desired:

SetAttributes[heldDistribute, HoldFirst]

heldDistribute[x_, args___] := Distribute[Unevaluated @ x, args]

f[a, b + c] // heldDistribute

f[1, 2] + f[1, 3]

heldDistribute[f[4, 5*7], Times]

f[4, 5] f[4, 7]

-
The Unevaluated prefix is what I was looking for. Cool. Thanks! – janitor048 Oct 23 '12 at 14:16

Distribute works if a and b are unevaluated

Distribute[f[a, b + c]]
(* f[a, b] + f[a, c] *)


If you want to ensure that the function is distributed before the evaluation of b+c you can use the HoldAll attribute.

SetAttributes[f, HoldAll]
Distribute[f[a, 5 + 3]]
(* f[a, 3] + f[a, 5] *)

-
Ok, the Hold-stuff is what I was missing. Thanks. One thing though. I need to set the HoldAll, Distribute and then clear the HoldAll for further evaluation. Is there a way to do this in one go? Or to set HoldAll temporary? – janitor048 Oct 23 '12 at 12:01
@janitor048 I don't see why you would need to clear HoldAll. Can you give an example? – Ajasja Oct 23 '12 at 12:09
Because in the next step the arguments of f need to be checked in some sort of pattern matching. More explicitly, f is the f from the answer by celtschk to this question mathematica.stackexchange.com/questions/13320/… – janitor048 Oct 23 '12 at 12:44
@janitor048 Aha. Well, there is Mr. Wizards answer now:) – Ajasja Oct 23 '12 at 13:10
Yep, I'm employing Mr. Wizards approach now as it allows to only temporarily hold f and later proceed with the normal f. But I will definitely keep in mind for later uses that one can permanently set a HoldAll attribute to generic functions. Thanks again. – janitor048 Oct 23 '12 at 14:15

A more convoluted version. Internal Hold is required so that Map does not evaluate 1+2+3.

SetAttributes[map, HoldAll];
map[func_, sum_Plus] := ReleaseHold@Map[func, Hold@sum, {2}];


Test:

map[f[a, #] &, x + y + z]


f[a, x] + f[a, y] + f[a, z]

map[f[a, #] &, 1 + 2 + 3]


f[a, 1] + f[a, 2] + f[a, 3]

-