I'm trying to write a Mathematica function that will format expressions according to my preferences, for example displaying (5 c x)/Sqrt[2]
as 5/Sqrt[2] c x
instead.
While attempting this I have come across some pattern matching behaviour that I don't understand, which reveals some holes in my understanding of the evaluation process.
As a simple example, consider the following:
Times[a, b, f[], c] /. Times[x__, f[], y__] :> {{x}, f[], {y}}
{{a}, f[], {b, c}}
I expected that this would output
{{a, b}, f[], {c}}
A Trace
gives the following output:
Column@Trace[Times[a, b, f[], c] /. Times[x__, f[], y__] :> {{x}, f[], {y}}]
{a b f[] c,a b c f[]} {{x__ f[] y__,f[] x__ y__},f[] x__ y__:>{{x},f[],{y}},f[] x__ y__:>{{x},f[],{y}}} a b c f[]/. f[] x__ y__:>{{x},f[],{y}} {{a},f[],{b,c}}
Clearly Times
is evaluating and shuffling its arguments to a standard form.
I will obviously have to apply HoldForm
or similar, but even at this stage I don't understand why the ReplaceAll
as shown in the Trace
outputs this result. (EDIT: To be clear, I don't understand why or how Mathematica has gotten a b c f[]
to match f[] x__ y__
, or why a
is matched by x__
and b
, c
are matched by y__
).
What approach should I apply to understand why this is the result?
Next, I try again while holding expressions:
HoldForm[Times[a, b, f[], c]] /. HoldPattern[Times[x__, f[], y__]] :> {{x}, f[], {y}}
{{a},f[],{b,c}}
And I still get the undesired result.
Here is the Trace
:
Trace[HoldForm[Times[a, b, f[], c]] /. HoldPattern[Times[x__, f[], y__]] :> {{x}, f[], {y}}]
{HoldPattern[x__ f[] y__]:>{{x},f[],{y}},HoldPattern[x__ f[] y__]:>{{x},f[],{y}}} a b f[] c/. HoldPattern[x__ f[] y__]:>{{x},f[],{y}} {{a},f[],{b,c}}
Now it appears as if Times
is not shuffling its arguments, but somehow along the way the b
has still been matched by y__
.
What is happening under the hood here?
And why is Trace
not showing it?
Finally now I remembered Verbatim
:
HoldForm[Times[a, b, f[], c]] /. Verbatim[Times][x__, f[], y__] :> {{x}, f[], {y}}
{{a,b},f[],{c}}
which gives the desired result.
Why does Verbatim
work better here than HoldPattern
?
I have been told before that Verbatim
is for "escaping the pattern matcher", but the argument Times
of Verbatim
hardly seems like something that the pattern matcher should care about.
So to summarise:
How do I understand what is happening under the hood when pattern matching with
Times
?Why did
Verbatim
work better thanHoldPattern
?
EDIT:
Thinking more about this line:
HoldForm[Times[a, b, f[], c]] /. HoldPattern[Times[x__, f[], y__]] :> {{x}, f[], {y}}
I don't understand how shuffling the arguments of Times[x__, f[], y__]
could cause y__
to match b c
, since b
and c
in the expression are separated by f[]
.
Is the pattern matcher able to shuffle the arguments of the expression even though it is contained in HoldForm
?
Times
isOrderless
and so its arguments are automatically sorted into canonical order? I still don't see whya
andb
,c
get matched by different blank sequences. $\endgroup$Print[Times[a, b, f[], c] /. Times[Longest[x__], f[], y__] :> {{x}, f[], {y}}]; Print[ Times[a, b, f[], c] /. Times[Shortest[x__], f[], y__] :> {{x}, f[], {y}}]
$\endgroup$