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?
Answer
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[]}}}}}}}}}}}}}}}}}}}}
Comments
Post a Comment