MathGroup Archive 2011

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

Search the Archive

Re: Question on Unevaluated

  • To: mathgroup at smc.vnet.net
  • Subject: [mg117308] Re: Question on Unevaluated
  • From: Leonid Shifrin <lshifr at gmail.com>
  • Date: Mon, 14 Mar 2011 06:10:43 -0500 (EST)
  • References: <201103131026.FAA20949@smc.vnet.net>

Alexey,

Doing what you request is generally not possible or at least extremely hard
(emulating exact behavior of Unevaluated in all cases), since Unevaluated is
one of the "magic symbols" (together with Evaluate and Sequence), wired deep
into the system. I discuss this a bit more here:

http://stackoverflow.com/questions/4856177/preventing-evaluation-of-mathematica-expressions/4856721#4856721

Regarding your particular request: it is an interesting exercise in working
with held expressions. Assuming
that we can only use Hold attributes, but neither Unevaluated nor Evaluate,
the following function will
(hopefully) work as if you had an attribute HoldN (that is, n-th argument
held, others not):

joinHeld[a__Hold] :=
  Hold @@ Replace[Hold[a], Hold[x___] :> Sequence[x], {1}];

splitHeldSequence[Hold[seq___], f_: Hold] := List @@ Map[f, Hold[seq]];

Clear[makeHoldN];
Module[{keepOnTop},
 makeHoldN[f_, n_Integer] :=
  (SetAttributes[f, HoldAll];
    f[args___] /; (! TrueQ[! keepOnTop]) :=
     Block[{keepOnTop = False},
      With[{result =
         If[n > Length[Hold[args]],
          f @@ {args},
          Apply[f,
           joinHeld @@
              Flatten[{Hold[##] & @@@ Take[#, n - 1], #[[n]],
                Hold[##] & @@@ Drop[#, n]}] &[
            splitHeldSequence@Hold[args]]]]},
       result /; Hold[result] =!= Hold[f[args]]]]) /;
   FreeQ[DownValues[f], keepOnTop]]

Here are some examples of use:

ClearAll[f]
makeHoldN[f, 2];
f[1^2, 2^2, 3^2]

f[1, 2^2, 9]


In[22]:= ClearAll[ff];
ff[args___] := Hold[args];
makeHoldN[ff, 3];
ff[1^2, 2^2, 3^2]

Out[25]= Hold[1, 4, 3^2]

One can rather easily generalize this to hold an arbitrary subsequence of
arguments (specified by
a list of their indices) while evaluating the rest. The implementation
employs a number of tricks.
One that needs a bit of clarification is the f[args___] /; (! TrueQ[!
keepOnTop]) line, since it serves
2 purposes. The one related to Block trick is well-known to you. The other
is that the presence of
condition involving a user-defined symbol makes it impossible for
Mathematica rule ordering
system to make conclusions about the generality of the rule, and therefore
the rule does not go
to the bottom of the rule list. This is needed because we want this rule to
stay at the top, to intercept
all calls to the function. For the same reason, makeHoldN should be called
already after all the
definitions have been given to the function, or the function will not work
properly.

As you see, this is sort of possible, but complex and error-prone.  In
practice, it is best to avoid
this sort of trickery, by changing the design of your functions. In my
experience, having HoldFirst,
HoldRest and HoldAll is quite enough. To evaluate any held argument, you can
also wrap it in
Evaluate. So, you particular question can be answered quite easily also as

SetAttributes[f,HoldAll];
f[Evaluate[Print[1]], Print[2], Evaluate[Print[3]]]

Note also, that I don't claim to reproduce exactly the behavior of
Unevaluated with my function above.
It is just an illustration of a possible poor man's device to accomplish the
specific goal of holding
n-th argument without the help of Evaluate and Unevaluated.

HTH

Regards,
Leonid


On Mon, Mar 14, 2011 at 1:06 AM, Alexey Popkov <lehin.p at gmail.com> wrote:

>  Leonid,
>
> Is it possible to imitate the behavior of Unevaluated by setting Attributes
> in this case:
>
> f[Print[1], Unevaluated[Print[2]], Print[3]]
>
> ?
>
> I am wondering, what attributes are temporarily set when we use Unevaluated
> and how could I imitate this?
>
> Alexey
>
>
>
> ----- Original Message -----
> *From:* Leonid Shifrin <lshifr at gmail.com>
> *To:* Alexey <lehin.p at gmail.com> ; mathgroup at smc.vnet.net
> *Sent:* Monday, March 14, 2011 1:39 AM
> *Subject:* Re: [mg117264] Question on Unevaluated
>
> Alexey,
>
> You forgot about the CompoundExpression (;). You only attempted to prevent
> the evaluation of 1+1 inside
> (1+1;3), but not the total result for CompoundExpression, which is the
> value of the last statement
> (2+1 in this case). This is what you probably had in mind:
>
> In[9]:= f[Unevaluated[(1 + 1; 2 + 1)]]
>
> Out[9]= f[Unevaluated[1 + 1; 2 + 1]]
>
> What is perhaps less obvious is that you did not prevent the evaluation of
> 1+1 either. Here is
> a simple way to check it:
>
> In[14]:= f[Unevaluated[Print["*"]]; 2 + 1]
>
> During evaluation of In[14]:= *
>
> Out[14]= f[3]
>
> The problem is that Unevaluated is only effective once. To totally prevent
> something from evaluation,
> you have to know the exact number of sub-evaluations (which is generally
> impossible to know since
> it can be data-dependent), and wrap in as many levels of Unevaluated. In
> this case,  the following will do:
>
> In[13]:= f[Unevaluated[Unevaluated[Print["*"]]]; 2 + 1]
>
> Out[13]= f[3]
>
> But as I said, this is not a robust approach, and in such cases you will be
> better to use Hold or similar for
> a persistent holding wrapper, stripping it off  later when needed. You may
> want to check out e.g. this thread
>
>
> http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/bfd67e9122b1fdec
>
> (my second post there), where I elaborate on these issues.
>
> HTH.
>
> Regards,
> Leonid
>
>
>
> On Sun, Mar 13, 2011 at 1:26 PM, Alexey <lehin.p at gmail.com> wrote:
>
>> Hello,
>>
>> I am puzzled a bit by the Documentation for Unevaluated. Under "More
>> information" field we read:
>>
>> "f[Unevaluated[expr]] effectively works by temporarily setting
>> attributes so that f holds its argument unevaluated, then evaluating
>> f[expr].".
>>
>> After reading this I expect that
>>
>> f[Unevaluated[1 + 1]; 2 + 1]
>>
>> will be returned completely unevaluated as it is when I set HoldFirst
>> attribute to f:
>>
>> In[2]:= SetAttributes[f, HoldFirst]
>> f[Unevaluated[1 + 1]; 2 + 1]
>>
>> Out[3]= f[Unevaluated[1 + 1]; 2 + 1]
>>
>> But in really we get
>>
>> In[1]:= f[Unevaluated[1 + 1]; 2 + 1]
>>
>> Out[1]= f[3]
>>
>> This leads me to a question: what is implied in documentation? Which
>> attributes are temporarily set and to which function?
>>
>>


  • Prev by Date: Re: Joining points of ListPlot
  • Next by Date: Re: Export strings to .pdf
  • Previous by thread: Question on Unevaluated
  • Next by thread: Re: Question on Unevaluated