Closed yuhan0 closed 3 years ago
Your intuition here is correct, I've done something similar in the past which can be generalized to this. The idea is to build a trie then derive an execution model from it. Good find :)
I guess there's also the assumption that individual keys are referentially transparent, and can actually be combined like so:
(inline/assoc-in {}
[(rand) :x] :oh
[(rand) :y] :no)
The above transform would change the behavior:
(let [m {}
r (get m (rand))]
(assoc m (rand)
(-> r
(assoc :x :oh)
(assoc :y :no))))
unless we use a heuristic that only atomic keys (keywords/symbols/numbers/strings) can be tested for equality and combined safely.
A heuristic is better than nothing. Dropping this here for reference, it can be adapted for a solution: https://github.com/bsless/impedance
@yuhan0 I opened a PR which should provide this feature, you're welcome to take a look
Sometimes when I want to do several updates on a deeply nested map, I end up writing something like this:
Replacing with the clj-fast inlined
assoc-in
does not help much, because there's still many redundant operations being made across macro boundaries (eg.(get m :x)
being calculated 4 times).Instead, it should be possible for a macro that takes multiple kv pairs to statically unroll it into something like:
I did a quick criterium benchmark and found it to be 6x faster than the naive version above, and 4.5x faster than a drop-in replacement of the inline/assoc-in.
I haven't looked too closely at the implementation details, but is this something that's achievable or within the scope of this library?
Thanks!