MathGroup Archive 1995

[Date Index] [Thread Index] [Author Index]

Search the Archive

Re: Challenge!

  • To: mathgroup at
  • 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>  
roth at (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

  • Prev by Date: Re: Random[Real,{0,1},$MachinePrecision] isn't MachineNumber[] ???!!
  • Next by Date: Challenge! ....RESULTS...
  • Previous by thread: Re: Challenge!
  • Next by thread: Re: Challenge!