This behavior of replacement rule seems inconsistent in Association
. First, the baseline example works as intended:
{ data[{1, 2, 3}], data[{3, 4}]} //
ReplaceAll[data[x_List] :> Length[x]]
{3, 2}
But in Association
<|"a" -> {1, 2, 3}, "b" -> {3, 4}|> // ReplaceAll[x_List :> Length[x]]
<|"a" -> Length[{1, 2, 3}], "b" -> Length[{3, 4}]|>
No problem with Map
:
<|"a" -> data[{1, 2, 3}], "b" -> data[{3, 4}]|> // ReplaceAll[data[x_List] :> x] // Map[Length]
<|"a" -> 3, "b" -> 2|>
Is this behavior by design or a bug?
Note, as per comment by Simon Woods, explicit Evaluate
on the right hand side of RuleDelayed has precedence over the replacement so can't be used as a workaround in ReplaceAll
- however, it works externally:
<|"a" -> {1, 2, 3}, "b" -> {3, 4}|> //
ReplaceAll[x_List :> Length[x]] // Map[Evaluate]
<|"a" -> 3, "b" -> 2|>
EDIT:
Following comments, and in Questions here and here and from WR support, HoldAllComplete causes this behavior.
Wouldn't it more appropriate if only the Keys were held? Keys are supposed to be treated Verbatim, not as patterns to be matched. But Values are intended to be transparent.
The current model introduces an inefficiency for deeply nested Associations: the need to (post)-Map Evaluate to Infinity to achieve the desired replacement.
Would appreciate feedback on this issue, and perhaps make the case to WR.
Evaluate@Length[x]
on the RHS of RuleDelayed it evaluates before the pattern is matched, so x has no value. Hence Length[x]=0 and Head[x]=Symbol $\endgroup$