Why does the following pattern matching not succeed?
ClearAll[f];
SetAttributes[f,Orderless];
HoldForm[f[a,d[],b,c]]/.HoldPattern[f[a,d[],b,z_]]:>{z}
(* f[a,d[],b,c] *)
I expected that because f
is Orderless
, the pattern matcher should try all possible orders of arguments and find a match.
If the expression is not held, I find:
ClearAll[f];
SetAttributes[f,Orderless];
f[a,d[],b,c]/.HoldPattern[f[a,d[],b,z_]]:>{z}
(* {c} *)
I.e. the desired result.
I know that because f
is Orderless
and the expression is evaluated, the arguments are sorted into canonical order a, b, c, d[]
.
It would appear in this case that the pattern matcher really does try all possible orders of arguments to find a match.
Why doesn't it work in the first example?
EDIT:
Here are some further examples:
ClearAll[f];
SetAttributes[f, Orderless];
Hold[f[a, b, c, d[]]] /. HoldPattern[f[a, b, c, z_]] :> {"Matched", {z}}
(* Hold[{"Matched", {d[]}}] *)
Hold[f[a, b, c[], d]] /. HoldPattern[f[a, b, c[], z_]] :> {"Matched", {z}}
(* Hold[{"Matched", {d}}] *)
Hold[f[a, b[], c, d]] /. HoldPattern[f[a, b[], c, z_]] :> {"Matched", {z}}
(* Hold[f[a, b[], c, d]] *)
Hold[f[a[], b, c, d]] /. HoldPattern[f[a[], b, c, z_]] :> {"Matched", {z}}
(* Hold[f[a[], b, c, d]] *)
This seems very inconsistent to me; how can I understand what is happening here?
EDIT:
An illuminating example:
Hold[f[a, c, b[], d]] /. HoldPattern[f[a, b[], c, z_]] :> {"Matched", {z}}
(* Hold[{"Matched", {d}}] *)
The Trace
shows no argument reordering, but it appears that the pattern matcher must actually be reordering the pattern to (the canonical order) f[a, c, b[], z_]
because f
is Orderless
, even though HoldPattern
should prevent "regular" evaluation.
What remains confusing is what exactly is meant by "In matching patterns with Orderless functions, all possible orders of arguments are tried." in the documentation. On face value, the four examples shown above contradict this.
HoldForm[f[a, d[], c]] /. HoldPattern[f[a, d[], c_]] :> {c}
outputs{c}
, and if you stopf
from beingOrderless
then the we likewise getHoldForm[f[a, d[], b, c]] /. HoldPattern[f[a, d[], b, c_]] :> {c}
outputting{c}
. It seems inconsistent to me. $\endgroup$Verbatim
trick works!HoldForm[f[a, d[], b, c]] /. Verbatim[f][a, d[], b, z_] :> {z}
yields{c}
. Although if you lose theHoldForm
, it doesn't work... $\endgroup$Verbatim
works becausef
is no longer treated as a head for pattern matching purposes, and so itsOrderless
attribute has no effect. But why that attribute prevents the match in the first place is unclear :/ $\endgroup$Verbatim
doesn't work without theHoldForm
on the expression, because the arguments of the expression will be sorted into canonical form but those of the pattern will not be able to shuffle, so there is no way for the pattern to match. $\endgroup$