I have found some other ways (than Block[...]
) to "force" the matching, but with some slight modifications of the code.
1. Whatever the choice you make here :
{f1, f2} = {Hold, Hold};
or
{f1, f2} = {HoldComplete, HoldComplete};
or
{f1, f2} = {Unevaluated, HoldPattern};
the two following approaches work (and give the same results) :
-> Using /;
: (this is actually the more compact solution)
MatchQ[f1[Times[3, 2, 2]], f2[Times[p : __ /; Length@{p} == 1]]]
MatchQ[f1[Times[3, 2, 2]], f2[Times[p : __ /; Length@{p} == 3]]]
(*False*)
(*True*)
-> Using a "trick" with /.
MatchQ @@ ({f1[Times[3, 2, 2]], f2[Times[a_]]} /. Times -> foo)
MatchQ @@ ({f1[Times[3, 2, 2]], f2[Times[_, _, _]]} /. Times -> foo)
(*False*)
(*True*)
Of course, instead of Times[_,_,_]
you could use conditional /;
or even pattern test ?
, to specify how many arguments Times should have (like in the previous solution) but this would produce a longer and less readable code.
2. All the previous code works not only when the arguments are numbers (Times[3,2,2]
) but also when they are just symbolic variables (Times[a,b,c]
)
For symbolic variables only, this also works :
Remove[a, b, c];
(**)
MatchQ[Times[a, b, c], _Times?(Length@# == 1 &)]
MatchQ[Times[a, b, c], _Times?(Length@# == 3 &)]
(*False*)
(*True*)
In comparison, neither this works :
MatchQ[Times[a, b, c], Times[x_, y_, z_]]
MatchQ[Times[a, b, c], Times[x_, y_]]
MatchQ[Times[a, b, c], Times[x_]]
(*True*)
(*True*)
(*True*)
nor the original test :
MatchQ[HoldComplete[Times[a, b, c]], HoldComplete[Times[x_, y_, z_]]]
MatchQ[HoldComplete[Times[a, b, c]], HoldComplete[Times[x_]]]
(*True*)
(*True*)
Flat
. $\endgroup$Flat
attribute ofTimes
. $\endgroup$