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:
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 :)