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 *)