Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

I had gotten used to thinking of the placement of a condition in a rule definition as logically immaterial. In my specific example, namely

ClearAll[f,g,h];
SetAttributes[f,HoldAllComplete];
f[x_ /; Head@Unevaluated@x === Symbol] := x;

SetAttributes[g,HoldAllComplete];
g[x_] := x /; Head@Unevaluated@x === Symbol;

SetAttributes[h,HoldAllComplete];
h[x_] /; Head@Unevaluated@x === Symbol := x;

all three produce the same results when applied to the same symbol

In[13]:= f[foo] === g[foo] === h[foo] === foo

(* Out[13]= True *)

But now I try to get fancy and write the following

ClearAll[f, g, h, foo];
SetAttributes[f,HoldAllComplete];
f[x_ /; Head@Unevaluated@x === Symbol] := Unevaluated@x;

SetAttributes[g,HoldAllComplete]
g[x_] := Unevaluated@x /; Head@Unevaluated@x === Symbol;

SetAttributes[h,HoldAllComplete]
h[x_] /; Head@Unevaluated@x === Symbol := Unevaluated@x;

In[20]:= {f[foo], g[foo], h[foo]}

and the results are very different

(* Out[20]= {foo, Unevaluated[foo], foo} *)

I try to figure it out with traceView2; I can see the differences

traceView2 differences

but I get quickly lost in the documents trying to understand what, why, and how. Seems even this example is not so simple and probes dark (at least to me) corners of the evaluator. I'd be grateful for advice, explanations, ideas.

share|improve this question
    
Related (possibly, even a dupe): mathematica.stackexchange.com/q/533/5 –  rm -rf Mar 19 '12 at 21:29
    
@R.M Not really a dupe -- this has more to do with the behavior of Unevaluated itself. Working on an answer now. –  Mr.Wizard Mar 19 '12 at 21:30
    
I love that traceview2 & 4 function. It is a lifesaver. I would +1 for the reference alone. –  tkott Mar 19 '12 at 21:35
    
A relevant discussion: stackoverflow.com/questions/6267143/… –  Leonid Shifrin Mar 19 '12 at 23:14
add comment

2 Answers 2

up vote 9 down vote accepted

This isn't a runtime issue, so you won't find the answer by tracing f[foo] and family.

It's a definition thing. If you look at the downvalues you'll see that in f as well as in h the Unevaluated got stripped off when running the SetDelayed

Let's look at the fullform of your definitions

f:

SetDelayed[
 f[Condition[Pattern[x, Blank[]], 
   SameQ[Head[Unevaluated[x]], Symbol]]],
 Unevaluated[x]]

So, Mathematica sees this code. First it evaluates SetDelayed, it is inert.

It checks its attributes: HoldAll, SequenceHold.

Now it strips off the Unevaluated of its arguments... (!!)

Evaluates the expression as a whole, and stores the definition (the Unevaluated is gone already)

g:

SetDelayed[
 g[Pattern[x, Blank[]]],
 Condition[Unevaluated[x], SameQ[Head[Unevaluated[x]], Symbol]]]

Now, in this case, no argument has head Unevaluated so it survives :)

h:

SetDelayed[
 Condition[h[Pattern[x, Blank[]]], 
  SameQ[Head[Unevaluated[x]], Symbol]], Unevaluated[x]]

Same as f, goodbye Unevaluated

share|improve this answer
1  
I see you had a quite different analysis, and it appears to be the correct one. –  Mr.Wizard Mar 19 '12 at 21:52
    
Interestingly, I think my observation is still valid, even if it does not directly apply here. –  Mr.Wizard Mar 19 '12 at 21:53
1  
Yeah, I agree. My answer is probably even confusing to someone that takes it as more general than it is intended... Yours shows the true spirit of Unevaluated –  Rojo Mar 19 '12 at 21:57
    
I'm a bit puzzled by the sentence "Strips Evaluate, evaluates the arguments with it". Which Evaluate? –  Sjoerd C. de Vries Mar 19 '12 at 22:14
    
@SjoerdC.deVries that was just a short attempt to be less particular. Makes no sense in this case because there's nothing to strip. I'm deleting it –  Rojo Mar 19 '12 at 22:15
show 11 more comments

This highlights a subtle difference in Condition expressions but at its heart I believe is the behavior of Unevaluated, not Condition.

Consider first:

List[Unevaluated[1 + 1], "foo"]

Plus[Unevaluated[1 + 1], "foo"]
{Unevaluated[1 + 1], "foo"}

2 + "foo"

Unevaluated is only stripped when Mathematica determines that further evaluation is necessary (or perhaps conversely, it remains when Mathematica does not evaluate). Consider now:

List[#, "foo"] & @ Unevaluated[1 + 1]
{2, "foo"}

Because the pure function is not HoldAllComplete an additional evaluation is triggered that does not occur when using List directly.

You can strip down your question example to this observation:

ff := Unevaluated[1 + 1]

gg := Unevaluated[1 + 1] /; True

{ff, gg}
{2, Unevaluated[1 + 1]}

Apparently the use of Condition causes Mathematica to consider that the RHS expression has already been evaluated.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.