Thread[...] does not seem to work as advertised
- To: mathgroup at smc.vnet.net
- Subject: [mg43265] Thread[...] does not seem to work as advertised
- From: "lwi" <none at nowhere.com>
- Date: Sat, 23 Aug 2003 08:08:44 -0400 (EDT)
- Sender: owner-wri-mathgroup at wolfram.com
Try this: In[1]:= fcntimes[v1_, v2_]:=h[v1 v2] In[2]:= fcndot[v1_, v2_]:=g[v1 . v2] In[3]:= Thread[fcntimes[{a1,a2},{b1,b2}]] Out[3]= {h[a1 b1],h[a2 b2]} This is the expected result. In[4]:= Thread[fcndot[{a1,a2},{b1,b2}]] Out[4]= g[a1 b1+a2 b2] This is not expected. (or at least not what I expected!) The expected result was {g[a1 . b1], g[a2 . b2]}, the result of threading "fcndot" over the lists in the arguments (as per documentation). Tracing shows what happened: (I have inserted spaces and line breaks in the output to improve readability) In[5]:= Trace[Thread[fcndot[{a1,a2},{b1,b2}]]] Out[5]= {{ fcndot[{a1,a2},{b1,b2}], g[{a1,a2}.{b1,b2}], {{a1,a2}.{b1,b2}, a1 b1+a2 b2}, g[a1 b1+a2 b2] }, Thread[g[a1 b1+a2 b2]], g[a1 b1+a2 b2] } "Thread" is actually being applied *after* its argument evaluates. Since in this case "fcndot" had a Dot[] function buried inside it that knew what to do with vector arguments, it effectively consumed the lists before they were presented to Thread. The behavior occurs because the argument of Thread is evaluated first, before "threading" takes place. Compare with: In[6]:= Trace[Thread[fcntimes[{a1, a2},{b1,b2}]]] Out[6]= {{ fcntimes[{a1,a2},{b1,b2}], h[{a1,a2} {b1,b2}], {{a1,a2} {b1,b2}, {a1 b1,a2 b2}}, h[{a1 b1,a2 b2}] }, Thread[h[{a1 b1,a2 b2}]], {h[a1 b1],h[a2 b2]} } Again, "Thread" is actually being applied to h[...], not to fcntimes[...], but this time the list is not consumed by h[...] so it is available to be presented to Thread. Although the sequence of evaluation is not what one might expect, for this function it makes no difference to the result. Finally, for comparison, In[7]:= fcntimes[{a1, a2},{b1,b2}] Out[7]= h[{a1 b1, a2 b2}] which is the expected result for Times when given vectors as its arguments, and In[8]:= fcndot[{a1, a2},{b1,b2}] Out[8]= g[a1 b1+a2 b2] which is identical to the result when the function was wrapped with Thread[...], but is the expected result in this case. Conclusion: Thread[f[{a,b},{c,d}] might return {f[a,c], f[b,d]} or it might return something else again, depending on the definition of f! But this is not what seems to be implied by the documentation of Thread. Shouldn't Thread have non-standard evaluation so that its performance conforms to the documentation? And, what is the idiom to use when you need to apply Dot[...] to a list of lists? (In other words, since Thread doesn't do the trick, how do I get the result I need, {g[a1.b1], g[a2.b2]}?)