This question was split from this one. While that question is now about how to match two particular patterns (mostly using Verbatim
or HoldPattern
), this question is about how to match any pattern with another one, in other words: "How can I test if a given pattern intersects with, or is a subset of another pattern?" (borrowed from Mr.Wizard). Consider the following examples where one can see that the left pattern should "match" the right one, but which all return False
:
MatchQ[a|b, b|a]
MatchQ[{a..}, {a..}]
MatchQ[{a..}, {a...}]
Of course one trivial way to deal with Alternatives
would be to simply Sort
its arguments:
MatchQ[a | b | c, Verbatim[Sort[b | c | a]]] ---> True
but things get complicated if the pattern involves more than Alternatives
.
Problem specification:
Therefore I am looking for a predicate function that compares any pattern with another pattern and decides whether the first one matches the second one. For this, one needs a general way of matching two expressions that may contain any of these operators: {|, .., ..., _, __, ___}
and possibly anything else that is specific for patterns. The predicate should have the following behaviour:
PatternMatchQ::usage="PatternMatchQ[e1, e2] returns True
if the set of expressions matched by pattern e1 is the same
or is a subset of the expressions matched by pattern e2, False otherwise."
i.e. the first pattern should cover the same (or smaller) domain as the second does. Now of course if any of the arguments is a non-pattern, PatternMatchQ
can fall back to MatchQ
.
Examples:
a|b
agrees withb|a
a|b
agrees withc|b|a
(asa|b
covers a domain that is covered bya|b|c
as well)a|b|c
does not agree withb|a
(asa|b|c
covers a domain that is larger than the domain covered byb|a
unlessc == a
orc == b
, in which case the pattern simplifies toa|b
){a..}
agrees with{a..}
{a..}
agrees with{a...}
{a...}
does not agree with{a..}
Extension:
Now the concept of matching can be extended in the following way. So far we were only concerned about whether it is true that $domain(e_1) \subseteq domain(e_2)$, and if not, return False
. But even if the test gives false, it is possible to define the smallest (most simple) domain that both patterns cover. Also, a full pattern-set-algebra emerges, if one thinks it further. Accordingly, for example PatternUnion
could work on any number of arguments, and should return the most general unifier of all the argument patterns. The union of patterns would be equivalent to the merging of patterns.
Now, of course, "The thing that hath been, it is that which shall be; and that which is done is that which shall be done: and there is no new thing under the sun"... in certain fields (e.g. in logic or in linguistics and especially in construction grammar), this method is called unification:
Two expressions $e_1$ and $e_2$ are said to unify iff there exists a substitution $s$ such that $s(e_1) = s(e_2)$
where a substitution is a binding of variables (i.e. implicit, hidden variables introduced by Mathematica to deal with e.g. _
, __
) in patterns $e_1$ and $e_2$ with actual fitting values. Note that the substituted value of a pattern-variable can be any atom, even symbols, it does not matter. Thus what the code should look for is the equality of variables (i.e. implicit pattern variables). If such an $s$ exists, it is called a unifier.
It is known that if two expressions $e_1$ and $e_2$ unify, then there always is only one most general unifier (up to a renaming of variables). Now this general unifier of two pattern expressions can be called (or used to describe) the intersection of $e_1$ and $e_2$.
Alternatives
but not theBlank..
orRepeated
families. I think aPatternUnion
would be much simpler than aPatternIntersection
(which could complement yourPatternMatchQ
) $\endgroup$Condition
andPatternTest
, I'm pretty sure that a general solution would need solving the halting problem. Therefore I guess any solution would need to either exclude those patterns, or need to be allowed to fail. There might be cases not using those constructs which are undecidable as well. $\endgroup$PatternIntersection
(without simplification) is even simpler implemented aspat1?(MatchQ[#,pat2]&)
. $\endgroup$