Re: Challenge!

*To*: mathgroup at christensen.cybernetics.net*Subject*: [mg998] Re: Challenge!*From*: villegas (Robert Villegas)*Date*: Mon, 8 May 1995 04:08:24 -0400*Organization*: Wolfram Research, Inc.

jorma.virtamo at vtt.fi (Jorma Virtamo) writes: > An alternative to write this is: > > If[Random[]<.5, First, Last] /@ Transpose[{list1, list2}] This idea works, but the implementation needs a slight correction. The problem with this function as written is that the If gets evaluated only once: at the beginning before the Map begins its work. Like most functions, Map lets its arguments be evaluated before it does its thing. So if list1 = {a, b, c, d, e} and list2 = {v, w, x, y, z}, the command will start out as Map[ If[Random[]<.5, First, Last], Transpose[{list1, list2}] ] but will get re-written as either of Map[ First, {{a, v}, {b, w}, {c, x}, {d, y}, {e, z}} ] or Map[ Last, {{a, v}, {b, w}, {c, x}, {d, y}, {e, z}} ] depending on the outcome of Random[]. The function being applied to all the elements is determined in advance. We want it determined anew for each element. Unevaluated will protect the function from pre-evaluation: In[21]:= Unevaluated[ If[Random[] < 0.5, First, Last] ] /@ Transpose[{list1, list2}] Out[21]= {v, b, c, d, z} With Unevaluated, the If statement itself, not its evaluation, is taken to be the function. Each time it is applied to an element, its value will be re-generated, sometimes becoming First, sometimes Last. You can see the general behavior in action by making up a simplified Map command and tracing it with and without the Unevaluated. One way to trace is with Trace or TracePrint. Compare the printouts of these two commands, and look for the If sequences. You'll see just one for the first command, but one at each element for the second command. I'm omitting the output since it's a little long (not horribly -- just around a page each) TracePrint[ If[Random[] < 0.5, f, g] /@ {x, y} ] TracePrint[ Unevaluated[If[Random[] < 0.5, f, g]] /@ {x, y} ] When you've seen several Trace outputs and feel a little more comfortable with what's going on, you can omit all but the If evaluations, just give a second argument of If: TracePrint[ If[Random[] < 0.5, f, g] /@ {x, y}, If ] TracePrint[ Unevaluated[If[Random[] < 0.5, f, g]] /@ {x, y}, If ] A different method to count the If evaluations is by switching on general tracing for the If function. Thanks to Dave Withoff for pointing out the usefulness of this window into the evaluator: In[31]:= On[If] In[32]:= Unevaluated[If[Random[] < 0.5, f, g]] /@ {x, y} If::trace: If[Random[] < 0.5, f, g] --> If[True, f, g]. If::trace: If[True, f, g] --> f. If::trace: If[Random[] < 0.5, f, g] --> If[False, f, g]. If::trace: If[False, f, g] --> g. Out[32]= {f[x], g[y]} The various Trace functions and option are discussed in section 2.5.10 of the Mathematica book. Also, there is a Tutorial on MathSource at http://www.wri.com/MathSource/Enhancements/Language/0203-858/Debugging.ma Robby Villegas