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.
f =!= g
. How can these be considered the same? If they are, what else is too? $\endgroup$f
andg
are never considered the same. When matching the patternf->f_
replaces the symbolf
with a pattern that (maybe confusingly so) is calledf
. You could equally well writef->x_
and then havex
matchf
andg
in each respectively. $\endgroup$f
andg
are not patterns, they are literals. $\endgroup$