开发者

Preventing evaluation of Mathematica expressions

开发者 https://www.devze.com 2023-02-07 23:29 出处:网络
In a recent SO question three different answers were supplied each using a different method of preventing the evaluation of the Equal[] expression.They were

In a recent SO question three different answers were supplied each using a different method of preventing the evaluation of the Equal[] expression. They were

  1. Defer[]
  2. Unevaluated[]
  3. HoldForm[]

Sometimes I still have trouble choosing between these options (and judging by answers to the before mentioned question, the choice isn't always clear for other people either). Can someone write a clear exposition on the use of these three methods?


There are three other wrappers Hold[], HoldPattern[], HoldComplete[], and the various Attributes for functions HoldAll, HoldFirst, HoldRest and the numeric versions NHold* that can also be discussed if you wish!

Edit

I just noticed that this is basically a repeat of the old question (which I had already upvoted, just forgotten...). The accepted answer linked to this talk at the 1999 Mathematica Developer Conference, which doesn't discuss Defer s开发者_C百科ince it is "New in 6". Defer is more closely linked to the frontend than the other evaluation control mechanisms. It is used to create an unevaluated output that will be evaluated if supplied in and Input expression. To quote the Documentation Center:

Defer[expr] returns an object which remains unchanged until it is explicitly supplied as Mathematica input, and evaluated using Shift+Enter, Evaluate in Place, etc.


Not touching Defer, since I did not work much with it and feel that in any given case its behavior can be reproduced by other mentioned wrappers, and discussing Hold instead on HoldForm (the difference is really in the way they are printed), here is the link to a mathgroup post where I gave a rather extensive explanation of differences between Hold and Unevaluated, including differences in usage and in the evaluation process (my second and third posts in particular).

To put the long story short, Hold is used to preserve an expression unevaluated in between several evaluations (for indefinite time, until we need it), is a visible wrapper in the sense that say Depth[Hold[{1,2,3}]] is not the same as Depth[{1,2,3}] (this is of course a consequence of evaluation), and is generally nothing special - just a wrapper with HoldAll attribute like any other, except being an "official" holding wrapper and being integrated much better with the rest of the system, since many system functions use or expect it.

OTOH, Unevaluated[expr] is used to temporarily, just once, make up for a missing Hold* attribute for a function enclosing expression expr. While resulting in behavior which would require this enclosing function to hold expr as if it had Hold* - attribute, Unevaluated belongs to the argument, and works only once, for a single evaluation, since it gets stripped in the process. Also, because it gets stripped, it often is invisible for the surrounding wrappers, unlike Hold. Finally, it is one of a very few "magic symbols", along with Sequence and Evaluate - these are deeply wired into the system and can not be easily replicated or blocked, unlike Hold - in that sense, Unevaluated is more fundamental.

HoldComplete is used when one wants to prevent certain stages of evaluation process, which Hold does not prevent. This includes splicing sequences, for example:

In[25]:= {Hold[Sequence[1, 2]], HoldComplete[Sequence[1, 2]]}

Out[25]= {Hold[1, 2], HoldComplete[Sequence[1, 2]]},

search for UpValues, for example

In[26]:= 
ClearAll[f];
f /: Hold[f[x_]] := f[x];
f[x_] := x^2;

In[29]:= {Hold[f[5]], HoldComplete[f[5]]},

Out[29]= {25, HoldComplete[f[5]]}

and immunity to Evaluate:

In[33]:= 
ClearAll[f];
f[x_] := x^2;

In[35]:= {Hold[Evaluate[f[5]]], HoldComplete[Evaluate[f[5]]]}

Out[35]= {Hold[25], HoldComplete[Evaluate[f[5]]]}   

In other words, it is used when you want to prevent any evaluation of the expression inside, whatsoever. Like Hold, HoldComplete is nothing special in the sense that it is just an "official" wrapper with HoldAllComplete attribute, and you can make your own which would behave similarly.

Finally, HoldPattern is a normal (usual) head with HoldAll attribute for the purposes of evaluation, but its magic shows in the pattern-matching: it is invisible to the pattern-matcher, and is very important ingredient of the language since it allows pattern-matcher to be consistent with the evaluation process. Whenever there is a danger that the pattern in some rule may evaluate, HoldPattern can be used to ensure that this won't happen, while the pattern remains the same for the pattern-matcher. One thing I'd stress here that this is the only purpose for it. Often people use it also as an escape mechanism for the pattern-matcher, where Verbatim must be used instead. This works, but is conceptually wrong.

One very good account on evaluation process and all these things is a book of David Wagner, Power programming with Mathematica - the kernel, which was written in 1996 for version 3, but most if not all of the discussion there remains valid today. It is out of print alas, but you might have some luck on Amazon (as I had a few years ago).


Leonid Shifrin's answer is quite nice, but I wanted to touch on Defer, which is really useful for only one thing. In some instances, it's nice to be able to directly construct expressions that won't be evaluated, but that a user will be able to easily edit; the basic example for this kind of behavior is button palettes that you can use to insert expressions or expression templates into input cells which the user can then edit as needed. This isn't the only way to do this, and for some more sophisticated applications you'll need to get into the hairy world MakeBoxes, but for the basics Defer will serve nicely.

0

精彩评论

暂无评论...
验证码 换一张
取 消