Skip to main content
added 3 characters in body
Source Link
WReach
  • 69.3k
  • 4
  • 165
  • 272

The observed behaviour will appear in any expression whose symbolic head has the attribute Flat.

Under normal circumstances, with no attributes in play, we see the usual expected behaviour:

MatchQ[f[1], f[1]]            (* True *)
MatchQ[f[1], f[a_]]           (* True *)
MatchQ[f[1], f[f[1]]]         (* False *)
MatchQ[f[1], f[f[a_]]]        (* False *)
MatchQ[f[1, 2, 3], f[a_]]     (* False *)

But when we introduce the Flat attribute, our normal intuition no longer holds:

SetAttributes[g, Flat]

MatchQ[g[1], g[1]]            (* True*True *)
MatchQ[g[1], g[a_]]           (* True*True *)
MatchQ[g[1], g[g[1]]]         (* True*True *)
MatchQ[g[1], g[g[a_]]]        (* True *)
MatchQ[g[1, 2, 3], g[a_]]     (* True *)

What is happening?

The purpose of Flat is to flatten out any nested expressions. That is, g[g[1, 2, 3]] is to be treated as equivalent to g[1, 2, 3]. The key point is that this equivalence works both ways. So when we ask whether g[1, 2, 3] matches the pattern g[a_], then this is equivalent to asking whether g[g[1, 2, 3]] matches g[a_]. Which of course it does. That is why the MatchQ expression in the question returns True. As does MatchQ[g[g[g[g[g[1, 2, 3]]]]], g[a_]]

Can we turn it off?

A simple way to perform the exact match requested by the question is to temporarily remove the Flat attribute from Times. Block will strip Times of all of its attributes:

Block[{Times}
, MatchQ[
    HoldComplete[Times[3, 2, 2]]
  , HoldComplete[Times[a_]]
  ]
]
(* False *)

If, for some reason, the application is such that we wish to retain the other attributes of Times, we can use Internal`InheritedBlock:

Attributes[Times]
(* {Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected} *)

Internal`InheritedBlock[{Times}
, Unprotect[Times]
; ClearAttributes[Times, Flat]
; Protect[Times]
; { MatchQ[
      HoldComplete[Times[3, 2, 2]]
    , HoldComplete[Times[a_]]
    ]
  , Attributes[Times]
  }
]
(* {False, {Listable, NumericFunction, OneIdentity, Orderless, Protected}} *)

The observed behaviour will appear in any expression whose symbolic head has the attribute Flat.

Under normal circumstances, with no attributes in play, we see the usual expected behaviour:

MatchQ[f[1], f[1]]            (* True *)
MatchQ[f[1], f[a_]]           (* True *)
MatchQ[f[1], f[f[1]]]         (* False *)
MatchQ[f[1], f[f[a_]]]        (* False *)
MatchQ[f[1, 2, 3], f[a_]]     (* False *)

But when we introduce the Flat attribute, our normal intuition no longer holds:

SetAttributes[g, Flat]

MatchQ[g[1], g[1]]            (* True*)
MatchQ[g[1], g[a_]]           (* True*)
MatchQ[g[1], g[g[1]]]         (* True*)
MatchQ[g[1], g[g[a_]]]        (* True *)
MatchQ[g[1, 2, 3], g[a_]]     (* True *)

What is happening?

The purpose of Flat is to flatten out any nested expressions. That is, g[g[1, 2, 3]] is to be treated as equivalent to g[1, 2, 3]. The key point is that this equivalence works both ways. So when we ask whether g[1, 2, 3] matches the pattern g[a_], then this is equivalent to asking whether g[g[1, 2, 3]] matches g[a_]. Which of course it does. That is why the MatchQ expression in the question returns True. As does MatchQ[g[g[g[g[g[1, 2, 3]]]]], g[a_]]

Can we turn it off?

A simple way to perform the exact match requested by the question is to temporarily remove the Flat attribute from Times. Block will strip Times of all of its attributes:

Block[{Times}
, MatchQ[
    HoldComplete[Times[3, 2, 2]]
  , HoldComplete[Times[a_]]
  ]
]
(* False *)

If, for some reason, the application is such that we wish to retain the other attributes of Times, we can use Internal`InheritedBlock:

Attributes[Times]
(* {Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected} *)

Internal`InheritedBlock[{Times}
, Unprotect[Times]
; ClearAttributes[Times, Flat]
; Protect[Times]
; { MatchQ[
      HoldComplete[Times[3, 2, 2]]
    , HoldComplete[Times[a_]]
    ]
  , Attributes[Times]
  }
]
(* {False, {Listable, NumericFunction, OneIdentity, Orderless, Protected}} *)

The observed behaviour will appear in any expression whose symbolic head has the attribute Flat.

Under normal circumstances, with no attributes in play, we see the usual expected behaviour:

MatchQ[f[1], f[1]]            (* True *)
MatchQ[f[1], f[a_]]           (* True *)
MatchQ[f[1], f[f[1]]]         (* False *)
MatchQ[f[1], f[f[a_]]]        (* False *)
MatchQ[f[1, 2, 3], f[a_]]     (* False *)

But when we introduce the Flat attribute, our normal intuition no longer holds:

SetAttributes[g, Flat]

MatchQ[g[1], g[1]]            (* True *)
MatchQ[g[1], g[a_]]           (* True *)
MatchQ[g[1], g[g[1]]]         (* True *)
MatchQ[g[1], g[g[a_]]]        (* True *)
MatchQ[g[1, 2, 3], g[a_]]     (* True *)

What is happening?

The purpose of Flat is to flatten out any nested expressions. That is, g[g[1, 2, 3]] is to be treated as equivalent to g[1, 2, 3]. The key point is that this equivalence works both ways. So when we ask whether g[1, 2, 3] matches the pattern g[a_], then this is equivalent to asking whether g[g[1, 2, 3]] matches g[a_]. Which of course it does. That is why the MatchQ expression in the question returns True. As does MatchQ[g[g[g[g[g[1, 2, 3]]]]], g[a_]]

Can we turn it off?

A simple way to perform the exact match requested by the question is to temporarily remove the Flat attribute from Times. Block will strip Times of all of its attributes:

Block[{Times}
, MatchQ[
    HoldComplete[Times[3, 2, 2]]
  , HoldComplete[Times[a_]]
  ]
]
(* False *)

If, for some reason, the application is such that we wish to retain the other attributes of Times, we can use Internal`InheritedBlock:

Attributes[Times]
(* {Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected} *)

Internal`InheritedBlock[{Times}
, Unprotect[Times]
; ClearAttributes[Times, Flat]
; Protect[Times]
; { MatchQ[
      HoldComplete[Times[3, 2, 2]]
    , HoldComplete[Times[a_]]
    ]
  , Attributes[Times]
  }
]
(* {False, {Listable, NumericFunction, OneIdentity, Orderless, Protected}} *)
Source Link
WReach
  • 69.3k
  • 4
  • 165
  • 272

The observed behaviour will appear in any expression whose symbolic head has the attribute Flat.

Under normal circumstances, with no attributes in play, we see the usual expected behaviour:

MatchQ[f[1], f[1]]            (* True *)
MatchQ[f[1], f[a_]]           (* True *)
MatchQ[f[1], f[f[1]]]         (* False *)
MatchQ[f[1], f[f[a_]]]        (* False *)
MatchQ[f[1, 2, 3], f[a_]]     (* False *)

But when we introduce the Flat attribute, our normal intuition no longer holds:

SetAttributes[g, Flat]

MatchQ[g[1], g[1]]            (* True*)
MatchQ[g[1], g[a_]]           (* True*)
MatchQ[g[1], g[g[1]]]         (* True*)
MatchQ[g[1], g[g[a_]]]        (* True *)
MatchQ[g[1, 2, 3], g[a_]]     (* True *)

What is happening?

The purpose of Flat is to flatten out any nested expressions. That is, g[g[1, 2, 3]] is to be treated as equivalent to g[1, 2, 3]. The key point is that this equivalence works both ways. So when we ask whether g[1, 2, 3] matches the pattern g[a_], then this is equivalent to asking whether g[g[1, 2, 3]] matches g[a_]. Which of course it does. That is why the MatchQ expression in the question returns True. As does MatchQ[g[g[g[g[g[1, 2, 3]]]]], g[a_]]

Can we turn it off?

A simple way to perform the exact match requested by the question is to temporarily remove the Flat attribute from Times. Block will strip Times of all of its attributes:

Block[{Times}
, MatchQ[
    HoldComplete[Times[3, 2, 2]]
  , HoldComplete[Times[a_]]
  ]
]
(* False *)

If, for some reason, the application is such that we wish to retain the other attributes of Times, we can use Internal`InheritedBlock:

Attributes[Times]
(* {Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected} *)

Internal`InheritedBlock[{Times}
, Unprotect[Times]
; ClearAttributes[Times, Flat]
; Protect[Times]
; { MatchQ[
      HoldComplete[Times[3, 2, 2]]
    , HoldComplete[Times[a_]]
    ]
  , Attributes[Times]
  }
]
(* {False, {Listable, NumericFunction, OneIdentity, Orderless, Protected}} *)