How to match expressions with a repeating pattern
New method
SetAttributes[test, HoldAll]
test[f[_] | f[_]@_?test] = True;
test[_] = False;
f[a]@f[b]@f[c] // test
True
This method's advantages are elucidated here:
- How to define a recursive pattern?
Old methods for reference
If subexpression evaluation is not a concern:
test = MatchQ[#, f[_] | f[_]@_?#0] &;
f[a]@f[b]@f[c] // test
True
To address Leonid's critique that this has evaluation leaks one might instead write:
p1 = HoldPattern @ f[_];
test = Function[, MatchQ[Unevaluated@#, p1 | p1@_?#0], HoldFirst];
Now it works here too:
f[b] = "FAIL!";
f[a]@f[b]@f[c] // test
True
@Mr.Wizard already picked the sweetest answer, but here is my version:
Function[Null,
Switch[Unevaluated@#,
HoldPattern[f[_]], True,
HoldPattern[f[_][_]], #0 @@ Unevaluated[#],
_, False],
HoldAll]
which is basically the same idea, but may be easier (or harder) to comprehend than his solution, depending on how you think. The pattern-matching is done as
MatchQ[f[a]@ f[b]@f[c],
_?(Function[Null,
Switch[Unevaluated@#,
HoldPattern[f[_]], True,
HoldPattern[f[_][_]], #0 @@ Unevaluated[#],
_, False],
HoldAll])]
(* True *)
Note that, if evaluation is not an issue, the above code can be simplified:
MatchQ[f[a]@f[b]@f[c], _?(Switch[#, f[_], True, f[_][_], #0 @@ #, _, False] &)]
Leonid and Mr.Wizard have given you good answers. Here's a highly unconventional solution that works when f
has no *Values
(i.e., it is undefined):
test[expr_, patt_] := NestWhile[First, expr, MatchQ[Head[#], patt] &] ~MatchQ~ patt
Some examples:
test[f[a]@f[b]@f[c], f[_]]
(* True *)
test[f[a]@g[b]@f[c], f[_]]
(* False *)
test[f[a]@f[b]@f[c, d], f[_]]
(* False *)