MathGroup Archive 2009

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

Search the Archive

Re: Help with HoldAll needed

  • To: mathgroup at smc.vnet.net
  • Subject: [mg100908] Re: [mg100891] Help with HoldAll needed
  • From: Leonid Shifrin <lshifr at gmail.com>
  • Date: Thu, 18 Jun 2009 04:51:17 -0400 (EDT)
  • References: <200906170845.EAA08859@smc.vnet.net>

Hi Erich,

Short answer: use Hold instead of Unevaluated:

In[1] =

ClearAll[MyFun];
SetAttributes[MyFun, HoldAll];
MyFun[x_] := Hold[x];

(in this example this means that you could bypass MyFun step and start
with Hold[2=3] from the beginning), and rules to deconstruct expressions:

In[2] =
MyFun[2 = 3] /. HoldPattern[a_ = b_] :> a

Out[2] = Hold[2]

It is actually safer  and easier to keep your expression wrapped in Hold and
use rules rather than play with attributes and evaluation. A more
interesting example:

In[3] =
code = Hold[Module[{a = 1, b, c = 2, d}, Print[a, b, c, d]]]

In[4] =
moduleVars =
 Cases[code,
  HoldPattern[
    Module[x_List, body_]] :> (Hold[x] /.
     HoldPattern[Set[y_Symbol, rhs_]] :> y), Infinity]

Out[4] = {Hold[{a, b, c, d}]}

Here we used this technique to introspect Module and extract variables
declared in it, in held form.


Now, a few remarks on your attempt:

1. If you really want to play games with evaluation, do yourself a favor and
read some detailed account on Mathematica evaluator, such as "Mathematica
Internals" by David Withoff (WRI technical report, available online at
Wolfram Library Archive), or a book by David Wagner (unfortunately, out of
print) -
this will save you hours of frustration.

2. Try to always set Attributes before making definitions for the function -
this is a generally correct way to do it, and there are (rather
pathological, but still) cases when this matters - see Guidebook for
Programming by Michael Trott for some examples. Here is one:


In[5] =

ClearAll[r, t, h];
r[x_ + y_] := x - y;
h[t[r[f_[x_] + g_[y_]]]] := f[x] - g[y];
SetAttributes[h, HoldAll];

In[6]= ?h

Out[6] =

Global`h
Attributes[h]={HoldAll}

h[t[f_[x_]-g_[y_]]]:=f[x]-g[y]

You see, the definition for <r> evaluated inside the l.h.s (declaration) for
<h> before the defining assignment for h evaluated. Now:

In[7] =

ClearAll[h];
SetAttributes[h, HoldAll];
h[t[r[f_[x_] + g_[y_]]]] := f[x] - g[y]

In[8] = ?h

Out[8] =
Global`h
Attributes[h]={HoldAll}

h[t[r[f_[x_]+g_[y_]]]]:=f[x]-g[y]

The reason for this behavior is that Set and SetDelayed only hold their
direct argument, not arguments of that argument. For example, in this case:

In[9] =
ClearAll[f, a];
a = 1;
f[a] = 5;

In[10] = ?f

Out[10] =
Global`f
f[1]=5

we might have naively expected the rule f[a] = 5 being added to the rule
base.
But <a> evaluated to 1, because evaluation of <a> is governed already by
attributes of <f>, not Set.

Now, the above example with <h> is indeed a pathological one, but there are
other less contrived situations where this is important as well. The worst
part here is that the trouble happens at the level of the function's
definition, and this is usully the last thing to suspect.


3. You don't need HoldAllComplete attribute. It is used typically to prevent

evaluator from taking any action on an expression, such as UpValue lookup
(which still happens with HoldAll). For most "standard" holding purposes
HoldAll will suffice.

4. The reason that Unevaluated does not work for you is that you use it
in an inappropriate setting - you should have used Hold instead.  Have a
look at the recent thread

http://groups.google.com/group/comp.soft-sys.math.mathematica/browse_thread/thread/bfd67e9122b1fdec?hl=en#

where there is a detailed discussion on the difference between Hold and
Unevaluated. To put it short, use Unevaluated only if you want some argument
to be passed to some function in unevaluated form locally, just once.
Unevaluated wrappers are stripped at the end of the given
evaluation, and then the new evaluation with a resulting expression
starts. Therefore, at the end of evaluation of <MyFun> you have just
expression 2 = 3 (Unevaluated stripped), and evaluator tries to evaluate
this and gives you an error message.

Here is the way to get what you want with Unevaluated, just for the record:

In[11] =

ClearAll[MyFun];
SetAttributes[MyFun, HoldAll];
MyFun[x_] := Unevaluated[Unevaluated[x]];

Clear[f];
f[x_]:=First[x];

In[12] = f[MyFun[2 = 3]] // Trace

Out[12] = {{MyFun[2=3],Unevaluated[2=3]},f[Unevaluated[2=3]],
First[Unevaluated[2=3]],First[2=3],2}

But this is error-prone: you have to explicitly count how many levels of
Unevaluated wrapper you need, so that when they are stripped you get the
desired outcome.

As I mentioned at the top of this post, when you wnat to preserve the result
in held (unevaluated) form in between two separate evaluations (which is
what you  need here), use Hold instead.

Finally, there is another way to "freeze" code -  use the Block trick. For
example, in this case:

In[13] = Block[{Set}, First[2 = 3]]

Out[13] = 2

This method has limitations: you can not Block symbols possessing Locked
attributes.

Hope this helps.

Regards,
Leonid
















On Wed, Jun 17, 2009 at 1:45 AM, Erich Neuwirth <erich.neuwirth at univie.ac.at
> wrote:

> I define
>
> MyFun[x_]:=Unevaluated[x]
> SetAttributes[MyFun,HoldAllComplete]
>
>
> MyFun[2 = 3]
> still evaluated the argument and of course produces an error
> I would like to get the unevaluated expression to be able
> to separate the first argument.
>
> In fact, I would like MyFun to be a macro which allows me
> to play list processing games with the arguments.
>
> How can this be accomplished?
>
>

--0016e6dbe2ae0651cb046c8be960
Content-Type: text/html; charset="ISO-8859-1"
Content-Transfer-Encoding: quoted-printable
X-Sun-Content-Length: 6574

Hi Erich,<br><br>Short answer: use Hold instead of Unevaluated:<br><br>In[1=
] = <br><br>ClearAll[MyFun];<br>SetAttributes[MyFun, HoldAll];<br>MyFun[x=
_] := Hold[x];<br><br>(in this example this means that you could bypass M=
yFun step and start<br>
with Hold[2=3] from the beginning), and rules to deconstruct expressions:=
<br><br>In[2] = <br>MyFun[2 = 3] /. HoldPattern[a_ = b_] :&gt; a<br><=
br>Out[2] = Hold[2]<br><br>It is actually safer  and easier to keep you=
r expression wrapped in Hold and use rules rather than play with attributes=
 and evaluation. A more interesting example:<br>
<br>In[3] = <br>code = Hold[Module[{a = 1, b, c = 2, d}, Print[a, b=
, c, d]]]<br><br>In[4] = <br>moduleVars = <br> Cases[code, <br>  Ho=
ldPattern[<br>    Module[x_List, body_]] :&gt; (Hold[x] /. <br>  =
   HoldPattern[Set[y_Symbol, rhs_]] :&gt; y), Infinity]<br>
<br>Out[4] = {Hold[{a, b, c, d}]}<br><br>Here we used this technique to i=
ntrospect Module and extract variables<br>declared in it, in held form.<br>=
<br><br>Now, a few remarks on your attempt:<br><br>1. If you really want to=
 play games with evaluation, do yourself a favor and read some detailed acc=
ount on Mathematica evaluator, such as &quot;Mathematica Internals&quot; by=
 David Withoff (WRI technical report, available online at Wolfram Library A=
rchive), or a book by David Wagner (unfortunately, out of print) - <br>
this will save you hours of frustration.<br><br>2. Try to always set Attrib=
utes before making definitions for the function - this is a generally corre=
ct way to do it, and there are (rather pathological, but still) cases when =
this matters - see Guidebook for Programming by Michael Trott for some exam=
ples. Here is one:<br>
<br><br>In[5] = <br><br>ClearAll[r, t, h];<br>r[x_ + y_] := x - y;<br>h=
[t[r[f_[x_] + g_[y_]]]] := f[x] - g[y];<br>SetAttributes[h, HoldAll];<br>=
<br>In[6]= ?h<br><br>Out[6] = <br><br>Global`h<br>Attributes[h]={Hold=
All}<br>
 <br>h[t[f_[x_]-g_[y_]]]:=f[x]-g[y]<br><br>You see, the definition for =
&lt;r&gt; evaluated inside the l.h.s (declaration) for &lt;h&gt; before the=
 defining assignment for h evaluated. Now:<br><br>In[7] = <br><br>ClearAl=
l[h];<br>
SetAttributes[h, HoldAll];<br>h[t[r[f_[x_] + g_[y_]]]] := f[x] - g[y]<br>=
<br>In[8] = ?h<br><br>Out[8] = <br>Global`h<br>Attributes[h]={HoldAll=
}<br> <br>h[t[r[f_[x_]+g_[y_]]]]:=f[x]-g[y]<br><br>The reason for this =
behavior is that Set and SetDelayed only hold their direct argument, not ar=
guments of that argument. For example, in this case:<br>
<br>In[9] = <br>ClearAll[f, a];<br>a = 1;<br>f[a] = 5;<br><br>In[10] =
= ?f<br><br>Out[10] = <br>Global`f<br>f[1]=5<br><br>we might have nai=
vely expected the rule f[a] = 5 being added to the rule base.<br>But &lt;=
a&gt; evaluated to 1, because evaluation of &lt;a&gt; is governed already b=
y attributes of &lt;f&gt;, not Set.<br>
<br>Now, the above example with &lt;h&gt; is indeed a pathological one, but=
 there are other less contrived situations where this is important as well.=
 The worst part here is that the trouble happens at the level of the functi=
on&#39;s definition, and this is usully the last thing to suspect.<br>
<br><br>3. You don&#39;t need HoldAllComplete attribute. It is used typical=
ly to prevent <br>evaluator from taking any action on an expression, such a=
s UpValue lookup (which still happens with HoldAll). For most &quot;standar=
d&quot; holding purposes HoldAll will suffice.<br>
<br>4. The reason that Unevaluated does not work for you is that you use it=
 <br>in an inappropriate setting - you should have used Hold instead.  Ha=
ve a <br>look at the recent thread <br><br><a href="http://groups.google.=
com/group/comp.soft-sys.math.mathematica/browse_thread/thread/bfd67e9122b1f=
dec?hl=en#">http://groups.google.com/group/comp.soft-sys.math.mathematica=
/browse_thread/thread/bfd67e9122b1fdec?hl=en#</a><br>
<br>where there is a detailed discussion on the difference between Hold and=
 Unevaluated. To put it short, use Unevaluated only if you want some argume=
nt to be passed to some function in unevaluated form locally, just once. Un=
evaluated wrappers are stripped at the end of the given <br>
evaluation, and then the new evaluation with a resulting expression <br>sta=
rts. Therefore, at the end of evaluation of &lt;MyFun&gt; you have just exp=
ression 2 = 3 (Unevaluated stripped), and evaluator tries to evaluate thi=
s and gives you an error message. <br>
<br>Here is the way to get what you want with Unevaluated, just for the rec=
ord:<br><br>In[11] = <br><br>ClearAll[MyFun];<br>SetAttributes[MyFun, Hol=
dAll];<br>MyFun[x_] := Unevaluated[Unevaluated[x]];<br><br>Clear[f];<br>f=
[x_]:=First[x];<br>
<br>In[12] = f[MyFun[2 = 3]] // Trace<br><br>Out[12] = {{MyFun[2=3]=
,Unevaluated[2=3]},f[Unevaluated[2=3]],<br>First[Unevaluated[2=3]],Fi=
rst[2=3],2}<br><br>But this is error-prone: you have to explicitly count =
how many levels of<br>
Unevaluated wrapper you need, so that when they are stripped you get the de=
sired outcome.<br><br>As I mentioned at the top of this post, when you wnat=
 to preserve the result in held (unevaluated) form in between two separate =
evaluations (which is what you  need here), use Hold instead.<br>
<br>Finally, there is another way to &quot;freeze&quot; code -  use the B=
lock trick. For <br>example, in this case:<br><br>In[13] = Block[{Set}, F=
irst[2 = 3]]<br><br>Out[13] = 2<br><br>This method has limitations: you=
 can not Block symbols possessing Locked attributes.<br>
<br>Hope this helps.<br><br>Regards,<br>Leonid<br><br><br><br><br><br><br><=
br><br><br><br><br><br><br><br><br><br><div class="gmail_quote">On Wed, J=
un 17, 2009 at 1:45 AM, Erich Neuwirth <span dir="ltr">&lt;<a href="mai=
lto:erich.neuwirth at univie.ac.at">erich.neuwirth at univie.ac.at</a>&gt;</span>=
 wrote:<br>
<blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, =
204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">I define<br>
<br>
MyFun[x_]:=Unevaluated[x]<br>
SetAttributes[MyFun,HoldAllComplete]<br>
<br>
<br>
MyFun[2 = 3]<br>
still evaluated the argument and of course produces an error<br>
I would like to get the unevaluated expression to be able<br>
to separate the first argument.<br>
<br>
In fact, I would like MyFun to be a macro which allows me<br>
to play list processing games with the arguments.<br>
<br>
How can this be accomplished?<br>
<br>
</blockquote></div><br>

--0016e6dbe2ae0651cb046c8be960--


  • Prev by Date: PDF re-pitch [Was: Re: What should be a simple task....]
  • Next by Date: Re: erroneous result when adding reals
  • Previous by thread: Help with HoldAll needed
  • Next by thread: Re: Help with HoldAll needed