4
$\begingroup$

RuleDelayed is a supported key/value wrapper in Associations.

What are general guidelines/idiomatic methods for working with such associations?

Specifically, how to Merge them:

ds = { 
  <|a :> Print[1], b -> 2|>
, <|a :> Print[2], b :> 1 + 1|>
};

Merge[Last] @ ds  
<|a :> Last[{Print[1], Print[2]}], b :> Last[{2, 1 + 1}]|>

For Merge[Last] case we can replace it with Association:

Association @ ds
<|a :> Print[2], b :> 1 + 1|>

But that is not general enough.

$\endgroup$
6
$\begingroup$

I'm not sure that it qualifies as a general idiom, but here is one way to address this specific case. First, we define a helper function that evaluates the right-hand side of a RuleDelayed expression:

evalRhs[k_ :> v_] := k :> # &[v]

Then we use that function to evaluate the Last expressions that become embedded within an intermediate association object by the Merge:

ds // Query[Merge[Last] /* AssociationMap[evalRhs], All, Unevaluated]

Unevaluated is applied to the individual key values to ensure that they maintain their unevaluated forms while the Last expression is evaluated. evalRhs will see expressions of the form:

key :> Last[{Unevaluated[value1], Unevaluated[value2], ...}]

By construction, the outer Last and List functions will be applied and then the remaining Unevaluated heads will be stripped in the calls to RuleDelayed.

Here is an extract from a trace of the evaluation, showing some key steps:

stack trace screenshot

General Strategy

Even though this solution is designed for the specific case at hand, we can extract a general strategy:

  • Apply the desired operator to the RuleDelayed key-values pairs (in this case, Merge[Last]).
  • Accept the fact that this will create an intermediate association with more complicated unevaluated expressions as values.
  • Perform selective evaluation of the values within the intermediate association.
  • Implement the selective evaluation using pattern-matching and evaluation control constructs. The exact form of that selective evaluation will need to be crafted to account for the operator that was initially applied and the desired results.
  • Accept the fact that selective evaluation control is a messy business generally, and doubly-so within associations :)
$\endgroup$
  • $\begingroup$ One thing I tend to use is a tagging Head that evaluates as Identity. Then I use ReplaceAll with that to do what I want with that tag. That avoids the RHS ballooning in complexity. $\endgroup$ – b3m2a1 Oct 24 '17 at 17:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.