Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

This is a follow-up to my (solved) question How to distribute a generic function of two arguments (without evaluating the arguments)

Say, I have a binary function

f[x : a_List, y : b_List] := g[a, b]

Now if

u={u1,u2};
v={v1,v2};
w={w1,w2};

I want do distribute f[u,v+w] prior to evaluating v+w which works fine with the solution proposed by Mr. Wizard to my previous question

Distribute[Unevaluated@f[u,v+w]]
(** g({u1,u2},{v1,v2})+g({u1,u2},{w1,w2}) **)

But now what if I do

expr = v + w;

and try to distribute f[u,expr]? I would like to get the same result as before, however this yields

f[u,expr]   
(** g({u1,u2},{v1+w1,v2+w2}) ** 

as of course v+w is evaluated when assigning to expr. Now a SetDelayed approach expr := v+w also doesn't help. I then thought of doing

expr = Hold[v+w];
Distribute[Unevaluated@ftest[u, ReleaseHold[expr]]]
(** g({u1,u2},{v1+w1,v2+w2}) **)

but this also gives the wrong (i.e. not the desired) result.

So, how do I do this?

share|improve this question
    
BTW: If anyone can think of a better title for this question, suggestions or edits would be highly welcome. I just don't really know how to put this problem into a concise title.. –  janitor048 Oct 24 '12 at 16:44

2 Answers 2

up vote 3 down vote accepted

You are better off thinking that in Mathematica you can control when and if an expression evaluates or not. But, if it evaluates, it does it until it doesn't change any more. In this case, you can make expr either stay as is, or evaluate

(1) expr -> (2) {v,w} -> (3) {{v1,v2}+{w1, w2}} -> (4) {{v1+w1, v2+w2}};

Actually, since your definition of expr is immediate (you used Set) it is actually stored as {{v1+w1, v2+w2}} already.

If you don't want that to happen, you have to change your design (for example, using a wrapper other than List for your vectors), or temporarily disable the definitions you want to hold. For the distributibity to work, the evaluation must stop at step (2) or (3)

Change your expr definition to a SetDelayed

expr := v + w;

and now either block Plus so it is no longer Listable while you distribute (step (3) ), or block your symbols (step (2) )

Block[{Plus}, Distribute@f[u, expr]]
Block[{v, w}, Distribute@f[u, expr]]
g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]    
g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]
share|improve this answer
    
That looks familiar. +1 –  Mr.Wizard Oct 24 '12 at 19:58
    
Hehe, good luck with the 400 bounty @Mr.Wizard –  Rojo Oct 24 '12 at 20:01
    
I'm not aiming for that. I don't really understand the problem, and even if I did I'm not sure I have much to offer. I did manage to fix an inefficient For loop, but that's about it. Nevertheless when I see someone put a big bounty on something I know they really want an answer, so I did what I could. –  Mr.Wizard Oct 24 '12 at 20:03
1  
Yeah, I'm also active today not for the rep... only to not focus on my work –  Rojo Oct 24 '12 at 20:05

Rojo got my favorite method already but for illustration here is a way to make your Hold approach work.

expr = Hold[v + w];

f[u, expr] /. h_Hold :> Distribute@h // Distribute // ReleaseHold
g[{u1, u2}, {v1, v2}] + g[{u1, u2}, {w1, w2}]
share|improve this answer
    
Good example of "changing the design". +1 –  Rojo Oct 24 '12 at 20:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.