15
$\begingroup$

A little while ago I wondered why

f[x_] = f[x]

gives an infinite iteration. I ended up discovering the following difference in evaluation between Set and SetDelayed with Evaluate.

count = 0;
ClearAll@a
a /; (count++ < 20) = {a}
a // OwnValues
count = 0;
a

Output

{{{{{{{{{{{{{{{{{{{{{a}}}}}}}}}}}}}}}}}}}}}
{HoldPattern[a /; count++ < 20] :> {a}}
{a}

and

count = 0;
ClearAll@b
b /; (count++ < 20) := Evaluate@{b}
b // OwnValues
count = 0;
b

Output

{HoldPattern[b /; count++ < 20] :> {b}}
{{{{{{{{{{{{{{{{{{{{b}}}}}}}}}}}}}}}}}}}}

Can somebody explain the difference? Can we say that there is an evaluation shortcut at work here?

Related

This is a follow up question: Strange results of definitions using OwnValues

Why x = x doesn't cause an infinite loop, but f[x_] := f[x] does?

Does Set vs. SetDelayed have any effect after the definition was done?

$\endgroup$
  • $\begingroup$ A nice tool I made says SetDelayed is not called in a usual way in the last example $\endgroup$ – Jacob Akkerboom Jan 10 '14 at 16:26
  • 2
    $\begingroup$ Ah, I see now. Thanks @Rojo $\endgroup$ – Mr.Wizard Jan 10 '14 at 17:13
  • 2
    $\begingroup$ It's another cache Update[] related mystery $\endgroup$ – Rojo Jan 10 '14 at 17:17
  • $\begingroup$ @Rojo I noticed the same thing myself. $\endgroup$ – Mr.Wizard Jan 10 '14 at 17:18
  • $\begingroup$ As to the second, there are several symbols that have special ways of being set. Perhaps through UpValues (or perhaps you like upcode better :P). Clearly the XValues are some of those. Perhaps, when they overloaded the SetDelayed versions, they forgot to return Null? $\endgroup$ – Rojo Jan 10 '14 at 17:22
3
$\begingroup$

I thought to give a bit more insight into why Update is needed, as pointed out in the other answers. Its documentation says Update may be needed when a change in 1 symbol changes another via a condition test.

In Jacob's example, setting count = 0 changes the condition test outcome, and thus a or b on the LHS. Consequently, a or b on the RHS is supposed to change. However, RHS a equals the old LHS a, which was undefined because count>=20, and needs Update to be changed. RHS b behaves the same, but was not evaluated in SetDelayed because Evaluate occurs before SetDelayed, so count is unchanged, and RHS b evaluates to LHS b with count<20. If we now reset count=0, evaluating b will return {b}.

To illustrate, I modify the example to separate LHS and RHS. MMA is clever enough to automatically update LHS declared as a variable, so I have to make a function:

count=0;
ClearAll[LHS,RHS];
LHS[]/;(count++<20)={RHS};
RHS=Unevaluated@LHS[];

count=0;
RHS (* Equals LHS[] with count >= 20 *)

(* Tell Wolfram Language about changes affecting RHS which depends on LHS *)
Update@Unevaluated@LHS;
RHS

LHS[]

{{{{{{{{{{{{{{{{{{{{LHS[]}}}}}}}}}}}}}}}}}}}}

$\endgroup$
  • $\begingroup$ Thanks for your answer, this seems to make sense and seems to have the right ingredients, but I will have to look at the details to fully understand and to be able to accept. $\endgroup$ – Jacob Akkerboom Aug 18 '16 at 14:39
  • $\begingroup$ @Jacob Thanks for the interesting question. I'm learning stuff I never thought about before. I'm looking at the link on infinite evaluation and trying to piece out the intricacies.. $\endgroup$ – obsolesced Aug 18 '16 at 15:28
3
$\begingroup$

Extended comment. Also: If Rojo wants to post an answer, I can delete this

It seems Rojo was right, guessing that it had to do with Update.

count = 0;
ClearAll@a2
a2 /; (Update[Unevaluated@a2]; count++ < 20) = {a2}
a2 // OwnValues
count = 0;
a2

Output

{{{{{{{{{{{{{{{{{{{{{a2}}}}}}}}}}}}}}}}}}}}}
{HoldPattern[a2 /; (Update[Unevaluated[a2]]; count++ < 20)] :> {a2}}
{{{{{{{{{{{{{{{{{{{{a2}}}}}}}}}}}}}}}}}}}}

I think user obsolesced rightly pointed out why there is an additional pair of brackets in the first output. This is because there is already a pair of brackets on the right hand side of Set and {a2} is evaluated rather than a2.

$\endgroup$
  • 1
    $\begingroup$ The number of braces is different because {a2} is output instead of a2. $\endgroup$ – obsolesced Aug 17 '16 at 9:39
2
$\begingroup$

Also an extended comment; using Update[] makes the first recursion behave as expected:

count = 0;
ClearAll@a
a /; (count++ < 20) = {a};
count = 0;
Update[]
a
{{{{{{{{{{{{{{{{{{{{a}}}}}}}}}}}}}}}}}}}}

Apparently the LHS condition is affected by the use of Set versus SetDelayed. Certainly worth more exploration, but for me that will have to wait.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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