Confusing title, I know. But the question is, if we have two patterns which have the same general structure but different names used in the patterns and different names:
a = HoldPattern[f[x_, y_, g_, h_]] :> g[x] + h[y];
b = HoldPattern[g[y_, z_, m_, l_]] :> m[y] + l[z];
And I would like to be able to define a pattern for these two pattens, letting {f,x,y,g,h} take arbitrary values. How would I go about this?
To clearify. If I had a=4;b=5
. I could define a common pattern through: _Integer
and get MatchQ[a,_Integer](*=>True*)
and MatchQ[b,_Integer](*=>True*)
.
But for my above two patterns, I cannot simply base my pattenr on a and substitute out {f,x,y,g,h} with _
eg:
badpattern = HoldPattern[f_[Pattern[x_,_], Pattern[y_,_],
Pattern[g_,_], Pattern[h_,_]]] :> h_[x_] + h_[y_];
I should not that what I want as a result is a working pattern not just a method that accomplishes this. Why? Well because the I would have to reimpliment MatchQ
, Cases
, Position
and so forth for everything that expects a pattern as it's input to still work. The code below accomplishes this, however in an ad-hoc fasion.
This is wrong since the result does not distinguish between structural Blanks, and pattern blanks.
My initial code
Just to get a pattern to match to itself I need to get rid of HoldPattern
which I do as:
MatchQ[a, a /. HoldPattern -> hp_ /; hp === HoldPattern]
(* True *)
Of cause I could just use Verbatim
however then I won't be able to do the next part. Where I extend the same type of pattern of switching out pattern components such as HoldPattern
.
To check b
against a pattern based on a
, I switch out a collection of heads inject new patterns and condition the pattern on the switched out heads:
myPatternPatternA=(a/.{HoldPattern->hp_,Pattern->p_,Blank->b_,RuleDelayed->rd_}
/.{f->f_,x-> x_,y-> y_,g-> g_,h-> h_ }
)/;And[hp===HoldPattern,p===Pattern,b===Blank,rd===RuleDelayed];
MatchQ[b,myPatternPatternA]
(* True *)
Note that I'm just using a as a template of the new pattern I construct, in the new pattern {f,x,y,g,h}
can all take arbitrary values since I'm injecting a new pattern for them after removing {HoldPattern,Pattern,Blank,RuleDelayed}
.
It seems however that I'll occasionally have problems with other symbols, which means I need to extend the list for instance to include Set
and SetDelayed
, however only when they actually appear in the expression, since otherwise the check fails. As such it feels like a rather cumbersome method. So I'm wondering if others have dealt with such cases and how they have carried this out.
Update
I should add that I'm relying on the matching to return values aswell, eg:
myPatternPattern = (a/.{HoldPattern->hp_,Pattern->p_,Blank->b_,RuleDelayed->rd_}
/.{f->f_,x-> x_,y-> y_,g-> g_,h-> h_ }
)/;And[hp===HoldPattern,p===Pattern,b===Blank,rd===RuleDelayed]:>f;
Cases[{a,b},myPatternPattern]
(*{f,g}*)
Mr. Wizard inquired as to what exactly I mean by the two definitions having the same structure. So I'll clarify. If we have two different expressions: f[3,4]
and g[2,5]
and I wanted to describe their structure, then I could write name_[_Integer,_Integer]
as one possible common structure. When I have two patterns this approach breaks down for obvious reasons, Consider; _[varA_]
and _[varB_]
. I would like to define a "pattern^2" that matches both of these patterns and assigns varA or varB to a name, so I just follow the same recipe as before and substitute varA
in the first with name_
and get: `_[_name_]
. This obviously fails. So what I have above is a way to define a pattern for patterns such that I can match elements inside them. Confusing, I know.
Answer
From a short discussion in Chat I think this question is going in a different direction. It may be a duplicate of How to match a pattern with a pattern? but perhaps more complicated than the examples there.
To illustrate how a pattern can be fully broken down:
a = HoldPattern[g[x_, y_, _, {1, 2}, q : {g_, h_}]] :> g[x] + h[y];
meta =
Replace[
HoldPattern @@ {a},
{Pattern -> Verbatim[Pattern], Blank -> Verbatim[Blank], HoldPattern -> Verbatim[HoldPattern]},
{2, -1},
Heads -> True
];
MatchQ[a, meta]
True
HoldPattern @@ {a}
and {2, -1}
is used to keep an outer HoldPattern
around the entire thing to prevent any unintentional evaluations.
Every part of meta
can be tagged with patterns and used as normal.
Since it doesn't make sense to me to assert that f
and g
literals are similar I shall ignore that for now. Consider this:
fill[pat_] := Range@Length@# /. # -> Extract[pat, 2, Hold] & @
Cases[pat[[1]], Quiet[Verbatim[Pattern][name_, _] :> name_], -1];
similar[a_, b_] := And[
SameQ @@ ({a, b}[[All, 1]] //. Verbatim[Pattern][_, x_] :> x),
SameQ @@ fill /@ {a, b}
]
Now:
a = HoldPattern[f[x_, y_, g_, h_]] :> g[x] + h[y];
b = HoldPattern[f[y_, z_, m_, l_]] :> m[y] + l[z];
similar[a, b]
True
Comments
Post a Comment