12

Executing:

replace[res_] := res /. {a_Integer, b_Integer} :> (a + b);
l1 = <|"respID" -> {1,2} , "key2" -> <|"key2" -> {2, 1}|>|>;
l2 = {"respID" -> {1,2} , "key2" -> {"key2" -> {2, 1}}};

replace[l1]
replace[l2]

In version 10.2 I get:

<|"respID" -> 3, "key2" -> <|"key2" -> 3|>|>
{"respID" -> 3, "key2" -> {"key2" -> 3}}

And in version 10.3:

<|"respID" -> 1 + 2, "key2" -> <|"key2" -> 2 + 1|>|>
{"respID" -> 3, "key2" -> {"key2" -> 3}}

Is this a bug? How can I force the evaluation as in 10.2, to prevent Hold[2+1] and get 3?


As a temporary solution I'm using a very clumsy function similar to this:

Needs["GeneralUtilities`"]
replace2[res_] := Module[{temp  = res/.Association-> List},
    temp = temp /. {a_Integer, b_Integer} :> (a + b);
    ToAssociations@temp
]
replace2@l1
<|"respID" -> 3, "key2" -> <|"key2" -> 3|>|>
Murta
  • 26,275
  • 6
  • 76
  • 166
  • Looks like a bug to me. Other workarounds would be forcing evaluation at replacement time using RuleCondition[a + b] as the RHS of the rule, or afterwards using eg Map[Identity, replace[l1], -1] – Simon Woods Jan 18 '16 at 21:34
  • 2
    @SimonWoods, RuleCondition is undocumented? Insteresting, replace[res_] := res /. {a_Integer, b_Integer} :> RuleCondition[a + b]; works. – Murta Jan 18 '16 at 21:38
  • See this for some more on RuleCondition – Simon Woods Jan 18 '16 at 21:40
  • @SimonWoods tks, interesting function. I'll use it. IMHO worth while an answer. – Murta Jan 18 '16 at 21:42
  • 5
    In fact, given that Association serves as HoldAllComplete container (after the key-value pairs have been added, they are not re-evaluated), the new behavior seems more logical to me than the old one. – Leonid Shifrin Jan 18 '16 at 22:18
  • Related: (89483) (your own question but linked for organizational purposes) – Mr.Wizard Jun 05 '16 at 00:07
  • @Leonid That is what I said in my answer to the question I just linked above, however Tali commented there to the contrary, unless I misunderstand him. – Mr.Wizard Jun 05 '16 at 00:11
  • 2
    @Mr.Wizard Not sure. I think the behavior of Replace reported there is fine, and as it should be. I will talk to Tali about this when I get a chance. – Leonid Shifrin Jun 05 '16 at 10:08

1 Answers1

4

As pointed out by Leonid Shifrin in comments, the behaviour you observe is not specific to associations, but is true of any function with the attribute HoldAll (or HoldAllComplete, or the relevant HoldFirst or HoldRest). As an example I use Hold. The simple rule {a_, b_}:>a+b does not force evaluation. To force it, you can use With in the right-hand side of the rule, and within it a condition: in order to find out whether the condition holds, Mathematica will have to evaluate the With construct, which injects the result in the right place.

Hold[{2, 3}] /. {a_Integer, b_Integer} :> a + b
Hold[{2, 3}] /. {a_Integer, b_Integer} :> With[{res = a + b}, res /; True]

(*gives
Hold[2 + 3]
Hold[5]
*)

Another option, as pointed out by Simon Woods, is to use RuleCondition[a + b] as the right-hand side, an undocumented function used under the hood to implement the With construction.

Bruno Le Floch
  • 1,959
  • 10
  • 23