There is no reordering: ReplaceRepeated
simply starts replacement from the outside of the expression. For example here the result is not f[g[g[1]]]
but:
f[f[f[1]]] //. f[f[x_]] :> g[g[x]] (* ==> g[g[f[1]]] *)
So in your case, the first rule that is matched is the second one, which happens to be more general (but it has nothing to do with evaluation order). Print
statements make it explicit that indeed the first rule is not tried at all:
a -> b //. {b -> (Print[1]; c), (x_ -> y_) :> (x -> (Print[2]; Expand[y]))}
During evaluation of In[12]:= 2
a -> b
There are at least two ways to overcome this. First, you can apply rules repeatedly from the inside (deepest-level-first). Giving explicit (reversed) level specifications to Replace
inside Fold
will do the replacements from inside->out.
expr = a -> b;
rules = {b :> (Print[1]; c), (x_ -> y_) :> (x -> (Print[2]; Expand[y]))};
Fold[Replace[#1, rules, {#2}] &, expr, Reverse@Range[0, Depth@expr]]
During evaluation of In[83]:= 1
During evaluation of In[83]:= 2
a -> c
Other way is to specify an explicit order of the rules to be applied:
Fold[ReplaceRepeated, expr, rules]
During evaluation of In[16]:= 1
During evaluation of In[16]:= 2
a -> c
Note that the two approaches are not identical: the second one might do repeated replacements per iteration of Fold
, while the first one only tries each rule once per iteration of Fold
.