Re: Challenge!
- To: mathgroup at christensen.cybernetics.net
- Subject: [mg954] Re: Challenge!
- From: villegas (Robert Villegas)
- Date: Thu, 4 May 1995 02:24:04 -0400
- Organization: Wolfram Research, Inc.
In article <3npp1t$od2 at news0.cybernetics.net> roth at sunny.mpimf-heidelberg.mpg.de. (Arnd Roth) writes: > In[1]:= swap[l1_List, l2_List] := ReleaseHold[Thread[ > Hold[If[Random[Integer] == 0, #1, #2] &][l1, l2]]] > > In[2]:= swap[{a, b, c, d, e, f, g}, {A, B, C, D, E, F, G}] > Out[2]= {a, B, C, d, E, f, g} > > In[3]:= swap[{a, b, c, d, e, f, g}, {A, B, C, D, E, F, G}] > Out[3]= {A, B, c, d, e, F, G} Arnd reminds us that we sometimes want to work with an expression without evaluating it. In general, you can send an argument intact to the code of a built-in function by wrapping it (the argument) in 'Unevaluated'. 'Unevaluated' is a flag to the main evaluator to keep its hands off. Standard evaluation procedure always evaluates all the arguments before giving them to the code of the function, unless the function has a Hold attribute (HoldFirst, HoldRest, or HoldAll) to prevent certain positions from being pre-evaluated. In the case of 'swap', we can wrap the function call in Unevaluated before doing the Thread: In[2]:= swap2[l1_List, l2_List] := Thread @ Unevaluated[If[Random[Integer] == 0, #1, #2]& [l1, l2]] In[3]:= swap2[{a, b, c, d, e, f, g}, {A, B, C, D, E, F, G}] Out[3]= {a, b, c, D, e, F, G} What happens is that the function call If[Random[Integer] == 0, #1, #2]& [{a, b, ...}, {A, B, ...}] is frozen when Thread gets it, so Thread effectively sees this structure f [{a, b, ...}, {A, B, ...}] where f is not important. Thread does its thing and creates a new list: {f[a, A], f[b, B], f[c, C], f[d, D], f[e, E], f[f, F], f[g, G]} This gets sent back up to top-level, where the evaluator carries out the calls to f (again, I'm using 'f' as shorthand for Arnd's pure function) before returning the final result. Unevaluated works in most of the functions you would use in programming. Some small examples: In[13]:= Position[Unevaluated[2^10 3^20 5^30 / (7^40 11^50)], p_^a_] Out[13]= {{1}, {2}, {3}, {4, 1, 1}, {4, 1, 2}, {4}} In[14]:= Count[Unevaluated[2^10 3^20 5^30 / (7^40 11^50)], p_^a_, -1] Out[14]= 6 In[15]:= LeafCount @ Unevaluated[2^10 3^20 5^30 / (7^40 11^50)] Out[15]= 19 One thing I've used it for a few times is mapping a function across a list without pre-evaluating the elements (the function itself is HoldFirst and deals with unevaluated things as it chooses): In[16]:= Attributes[f] = HoldFirst Out[16]= HoldFirst In[17]:= f /@ Unevaluated[{1 + 2, 3 - 4}] Out[17]= {f[1 + 2], f[3 - 4]} Of course, this can be dealt with by temporarily employing Hold and then discarding it, but the Unevaluated is somewhat more direct, because you're working with the objects you want from the start. Unevaluated is discarded at the end if the expression it wrapped got "used up" by code (i.e. some transformation rule was applicable to it). It's been very useful in some functions I use that have to maintain things unevaluated. The steps of evaluation are listed in detail in Dave Withoff's "Mathematica Internals" chapter in the _Selected Tutorial Notes_ that Dave Wagner referred to for numerics. Robby Villegas