29

While playing around with the solutions to this question, I've found some very strange behaviour:

MatchQ[3,_?Composition[Not,OptionQ]]
(*
==> False
*)
MatchQ[3,_?(Not[OptionQ[#]]&)]
(*
==> True
*)
Composition[Not,OptionQ][3]
(*
==> True
*)

So what's wrong with the first pattern? Or did I just find some bug?

celtschk
  • 19,133
  • 1
  • 51
  • 106

1 Answers1

31

Because PatternTest binds very tightly. You need extra parentheses:

MatchQ[3, _?(Composition[Not, OptionQ])]
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • Thanks. I should have thought of that possibility myself ... – celtschk Feb 13 '12 at 16:44
  • 7
    @celtschk This is not at all obvious - it binds stronger than a function call: a?f[b] // FullForm gives PatternTest[a,f][b], which is not something we are used to. I just happened to have been bitten by this a few times. The same story with the Function: have to wrap it in parentheses as well. I actually mentioned that in my answer to the question you linked. – Leonid Shifrin Feb 13 '12 at 16:46
  • 8
    This is one reason I tend to use Condition for anything that isn't completely trivial... – Brett Champion Feb 13 '12 at 16:46
  • @Brett I use PatternTest in this form with parentheses quite a bit as well, but I agree that there are less chances for errors with Condition. – Leonid Shifrin Feb 13 '12 at 16:50
  • 5
    It's unusual for something to have a higher precedence than [...] function call ... – Szabolcs Feb 13 '12 at 16:50
  • @Szabolcs Yes, that's what I also said in the comments. This is why this can be very puzzling. – Leonid Shifrin Feb 13 '12 at 16:52
  • As another example of this behavior, note that a_b[c] // FullForm ->Pattern[a,Blank[b]][c] – Jacob Akkerboom Mar 06 '13 at 11:35
  • @JacobAkkerboom That's a good point. But this is probably less frequent use case. – Leonid Shifrin Mar 06 '13 at 11:45