Using ReplaceAll to replace a head
Use Replace
instead of ReplaceAll
Replace[a[b[c, d]], head_[arg__] :> newHead[arg], {0, Infinity}]
newHead[newHead[c, d]]
ReplaceAll
fails to do what you want because it acts from the outside in. Once it found a match (the entire expression) on the outside, its job was done. Replace
on the other hand, acts from inside out.
This question has essentially been asked many times before, perhaps most recently here:
- Converting hierarchies of rules to associations
I addressed it myself when I demonstrated the use of Replace
and FixedPoint
in place of ReplaceRepeated
to get the standard traversal in:
- ReplaceRepeated seemingly omits some rules
As already explained by RunnyKine ReplaceAll
and ReplaceRepeated
traverse the expression in an unusual way within the context of Mathematica. See my self-Q&A for some examples:
- How to perform a depth-first preorder traversal of an expression?
Further, as stated in the documentation:
ReplaceAll looks at each part of expr, tries all the rules on it, and then goes on to the next part of expr. The first rule that applies to a particular part is used; no further rules are tried on that part, or on any of its subparts.
Combined with the traversal order this means that inner expressions will never be replaced if they are part of a larger expression that matches a rule.
mfvonh comments that you could use:
a[b[c, d]] //. (head : Except[newHead])[arg__] :> newHead[arg]
newHead[newHead[c, d]]
However this is inefficient as the entire expression is rescanned for each replacement. I explored this issue in some detail here:
- How to remove redundant {} from a nested list of lists?
seismatica wrote:
I think I now know (how)
ReplaceAll
scans an expression. I'm still confused about how it replaces its matches. For exampleh[h[u, h], h] /. x : head_[arg__] /; Print[x] :> x
finds all headsh
, yeth[h[u, h], h] /. h[arg__] :> k[arg]
only replaces the outermosth
. @mfvonh mentions in his comment that "ReplaceAll "quits" because it replaces the whole expr and doesn't test the new part". If that's the case, then why wouldh[h[u, h], h] /. h :> k
even though when anyh
is replaced, the expressions would also change.
Each case you cite is different from the original. In the first example you use a Condition
that never is True
, therefore every part of the expression that matches the pattern (without the condition) is checked (and printed) as ReplaceAll
searches in vain for a match. Note how the behavior changes if we use a condition that is always True
:
h[h[u, h], h] /. x : head_[arg__] /; (Print[x]; True) :> x
h[h[u,h],h]
h[h[u, h], h]
The second example highlights an important yet perhaps subtle difference: only entire expressions that are replaced are skipped for further matching and replacement. An expression head is like any other part of an expression and it can be replaced independently, therefore you can use /.
to replace all heads of a certain kind (or which match a certain pattern) but you must not include arguments along with them.
Consider these examples:
SeedRandom[0]
expr = RandomInteger[9, {3, 2, 3}]
{{{7, 0, 8}, {2, 1, 5}}, {{8, 0, 6}, {7, 2, 1}}, {{0, 6, 1}, {2, 8, 6}}}
expr /. {x__} :> h[x]
h[{{7, 0, 8}, {2, 1, 5}}, {{8, 0, 6}, {7, 2, 1}}, {{0, 6, 1}, {2, 8, 6}}]
expr /. List -> h
h[h[h[7, 0, 8], h[2, 1, 5]], h[h[8, 0, 6], h[7, 2, 1]], h[h[0, 6, 1], h[2, 8, 6]]]
This head replacement can be used, for example, to sort all lists:
expr /. List -> Composition[Sort, List]
{{{0, 1, 6}, {2, 6, 8}}, {{0, 6, 8}, {1, 2, 7}}, {{0, 7, 8}, {1, 2, 5}}}