Related question concerning unrolling the tests that are shown below:
Big and Little surprises when unrolling tests of pattern-matching and attributes
Questions researched before posting this one:
Combinations of multiple matching patterns
What has changed in pattern matching functions with the Orderless attribute?
Transformation rule for arbitrary number of argument expressions
Pattern does not match with Orderless head
In an attempt to understand pattern-matching better, I tried some exhaustive testing of a certain substitution rule under all seven combinations of attributes, leaving out the null case of no attributes:
In[1]:= allAtts =
Flatten[Table[
Union[Sort /@
Permutations[{Flat, Orderless, OneIdentity}, {i}]], {i, 3}], 1]
Out[1]= {{Flat}, {OneIdentity}, {Orderless}, {Flat, OneIdentity}, {Flat,
Orderless}, {OneIdentity, Orderless}, {Flat, OneIdentity,
Orderless}}
The substitution rule attempts to match the pattern eqv[x_, y_]
against the input eqv[p, q, r]
to see what gets bound to x
and y
for each combination of attributes.
In the first test, I define the substitution before setting the attributes. After some manual prettification of the output:
In[2]:= Table[Module[{e = (eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}})},
ClearAll[eqv];
SetAttributes[eqv, j];
{j, First@e, Rest@e}],
{j, allAtts}]
Out[2]= {{{Flat}, p, eqv[q, r]},
{{OneIdentity}, eqv[p], {eqv[q, r]}},
{{Orderless}, p, eqv[q, r]},
{{Flat, OneIdentity}, p, eqv[q, r]},
{{Flat, Orderless}, p, {eqv[q, r]}},
{{OneIdentity, Orderless}, q, {eqv[p, r]}},
{{Flat, OneIdentity, Orderless}, p, eqv[q, r]}}
The results are reasonable, plausible, interpretable.
In a second test (not-unrolled; see cited question above), I set the attributes before defining the substitution rule. The results are subtly different.
In[3]:= Table[Module[{e},
ClearAll[eqv];
SetAttributes[eqv, j];
e = (eqv[p, q, r] /. {eqv[x_, y_] :> {x, y}});
{j, First@e, Rest@e}],
{j, allAtts}]
Out[3]= {{{Flat}, eqv[p], {eqv[q, r]}}, (* difft *)
{{OneIdentity}, p, eqv[q, r]}, (* difft *)
{{Orderless}, p, eqv[q, r]},
{{Flat, OneIdentity}, p, {eqv[q, r]}}, (* difft *)
{{Flat, Orderless}, q, {eqv[p, r]}}, (* difft *)
{{OneIdentity, Orderless}, p, eqv[q, r]}, (* difft *)
{{Flat, OneIdentity, Orderless}, p, {eqv[q, r]}}} (* difft *)
My questions are:
Why, exactly, are there such differences? I understand that order-of-evaluation matters quite a bit, in general, in Mathematica, but it's hard for me to understand these particular differences. Details follow in the rest of my questions:
In the first test, with
Flat
alone, why do I get (a)p
wrapped ineqv
, i.e.,eqv[p]
andeqv[q, r]
wrapped inList
, when I set attributes before defining the substitution rule?In the second test, for
OneIdentity
, alone, when attributes are set before the substitution rule is defined, do I get the same results as forFlat
, alone, when the substitution rule is defined before the attributes are set? In other words, for the two orders of attributes-setttings versus rule-defining, are the results forFlat
alone andOneIdentity
alone swapped?In the fourth test, for
{Flat, OneIdentity}
, why do I get no wrapping withList
for the second substitution (fory
) when the substitution rule is defined before the attributes are set, and yes wrapping withList
when the attributes are set before the substitution rule is defined?In the fifth test, for
{Flat, Orderless}
, why do I getp
forx
when the substitution rule is defined before attributes are set, andq
forx
when the attributes are set before the substitution rule is defined?In the sixth test, for
{OneIdentity, Orderless}
, there are two differences between the two conditions (substitution rule defined before attributes set, and attributes set before substitution rule defined). The first difference (a) is that I getq
forx
in the first condition andp
forx
in the second condition. The second difference (b) is that I getList
wrapping in the first condition and noList
wrapping in the second condition.
EDIT: I missed the last difference in the original, and finding it gave me an opportunity to ask the sharpest questions:
- In the seventh test, for all three attributes, I get an extra
List
wrapping in the output in the second condition, attributes-set before substitution-defined. Why is that? Should I have been able to predict it knowing just the conditions? By what reasoning?
I apologize for the length and complexity of this question, but I made it as short and as simple as I know how to. This question reveals that I don't know nearly as much as I thought I did about pattern-matching and attributes. Perhaps after I learn more from you-all, a much simpler form of the essential question --- hiding in here somewhere I hope --- will emerge.
e
in your output, you will see that the replacement only did something when Flat was one of the attributes. $\endgroup$