17
$\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$
6
  • $\begingroup$ A nice tool I made says SetDelayed is not called in a usual way in the last example $\endgroup$ Commented Jan 10, 2014 at 16:26
  • 2
    $\begingroup$ Ah, I see now. Thanks @Rojo $\endgroup$ Commented Jan 10, 2014 at 17:13
  • 2
    $\begingroup$ It's another cache Update[] related mystery $\endgroup$ Commented Jan 10, 2014 at 17:17
  • $\begingroup$ @Rojo I noticed the same thing myself. $\endgroup$ Commented Jan 10, 2014 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$ Commented Jan 10, 2014 at 17:22

3 Answers 3

5
$\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$
2
  • $\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$ Commented Aug 18, 2016 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$ Commented Aug 18, 2016 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
  • 1
    $\begingroup$ The number of braces is different because {a2} is output instead of a2. $\endgroup$ Commented Aug 17, 2016 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$
0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.