9

The following input:

Cases[{"key" -> Association[]}, HoldPattern["key" -> Association[]]]

Returns {}. Why does it not return {"key" -> Association[]}? I was expecting it to match.

m_goldberg
  • 107,779
  • 16
  • 103
  • 257
Ramiro Magno
  • 325
  • 1
  • 10
  • 2
    You should use Verbatim for that. HoldPattern is for patterns – RunnyKine Apr 19 '16 at 15:43
  • @RunnyKine I thought I would use HoldPattern to treat the rule itself as a pattern, otherwise the rule is interpreted by Cases (as discussed here: http://mathematica.stackexchange.com/questions/112333/pattern-matching-for-rules/112335) – Ramiro Magno Apr 19 '16 at 15:53
  • 6
    The subtle point here is that Association[] evaluates to <||>, and even though the FullForms of the two are the same, SameQ on them gives False, because the constructor Association[] does a non-trivial job when evaluated, and the result of it is not a normal expression Association[], but a new atomic object. So, we have Unevaluated[Association[]] === Association[] producing False. Therefore, MatchQ[Association[], HoldPattern[Association[]]] gives False, while of course MatchQ[Association[], HoldPattern[Evaluate@Association[]]] gives True. – Leonid Shifrin Apr 19 '16 at 15:58
  • 1
    @LeonidShifrin: very interesting. I keep forgetting Association is an atomic expression. But how would you suggest I do the matching with Cases? Inspired by your MatchQ example I can see that Cases[{Association[]}, HoldPattern[Evaluate@Association[]]] matches, but it won't match if the expression containing Association is a Rule. For instance: Cases[{"key" -> Association[]}, HoldPattern["key" -> Evaluate@Association[]]] won't match. – Ramiro Magno Apr 19 '16 at 16:31
  • 3
    Use Verbatim, as @RunnyKine suggested. Since it does not prevent evaluation of parts of the pattern, you will then compare evaluated / constructed Association[] in your expression with a similarly evaluated Association[] inside the pattern. Or, much simpler, if you don't care whether or not association is empty, you could use _Association pattern, which is matched in both cases. – Leonid Shifrin Apr 19 '16 at 16:39

1 Answers1

12

To answer the question of why there is no match let's look at the output of Trace:

Cases[{"key" -> Association[]}, HoldPattern["key" -> Association[]]] // Trace

(* {{{{Association[], <||>}, "key" -> <||>, "key" -> <||>}, 
  {"key" -> <||>}}, Cases[{"key" -> <||>}, HoldPattern["key" -> Association[]]], {}} *)

We see that Association[] gets evaluated to <||>, which as Leonid states is not a normal expression and so will not match Association[]. As I suggested in the comments, I think the right approach in this and similar situation where an evaluation might occur with Association[], is to use Verbatim:

Cases[{"key" -> Association[]}, Verbatim["key" -> Association[]]]

(* {"key" -> <||> } *)

If you look at the Trace of the expression, you'll see why it matched.

Cases[{"key" -> Association[]}, Verbatim["key" -> Association[]]] // Trace

Verbatim allows its input to also evaluate, hence both expressions now look the same: "key" -> <||>, hence the match. Finally, if for some reason you really want to use HoldPattern, then I suggest wrapping your expression in Unevaluated:

Cases[Unevaluated[{"key" -> Association[]}], HoldPattern["key" -> Association[]]]

(* {"key" -> <||> } *)
gwr
  • 13,452
  • 2
  • 47
  • 78
RunnyKine
  • 33,088
  • 3
  • 109
  • 176