`map-nested` or something
gfredericks opened this issue · comments
For years and years and years and years I keep running into the issue of how awkward it is to mix threading macros with updating the values in a collection.
I'm not sure if this can be made easier without getting into crazy-threading-macro-complexity-hell or something like that, but I thought I would check if you folks have some alternate approach, or if we might discover a decent extension for plumbing.
To be concrete, I often find myself doing something like:
(defn the-business-logic
[m]
(-> m
(update :logic-count inc)
(update :clients (fn [clients] (map (fn [client]
(-> client
(update-in ...)))
clients)))))
This could also be accomplished with (partial map (fn [client] ...))
or even nicer with the fn->
I just re-discovered a few minutes ago, but it still feels like it takes a lot of work to map a nested collection.
Approaches using functions that don't exist yet:
- The super higher-order
(defn flip [f] (fn [x y] (f y x)))
could be used to say(update :clients (flip map) (fn-> ...))
- I once defined a
map-nested
that let me do(map-nested :clients (fn-> ...))
I dunno!
One nice thing about flip
is that it would also work with other sorts of wrong-order functions like map-vals
, map-keys
, etc.
@gfredericks If you're not set on composing these transformations yourself, libraries like spectre and instar both provide power-update
style functions which make exactly those sorts of examples simple and declarative.
Understand your gist here is chasing simple, composable pieces, but decided to crash this party anyway 👪
Thanks for the pointers; spectre is definitely too much macro for me, and I think you're right that I'd prefer the composable pieces to a more comprehensive approach.
I can grant that comprehensive approaches might do everything I want, but the social cost of adopting a large thing is pretty high.
No arguments there!
A map
+ fn->
combination to me than update
+ map
. Obliviates the need for map-nested-in
.
(defn the-business-logic [m]
(-> m
(update :logic-count inc)
(update :clients (each-> (update-in ...)))))
The each->
function could preserve the collection type too I guess.
Our usual idiom is e.g.
(update x :clients (fn->> (map #(update % :foo inc))))
I guess with something like flip
you can drop a level of nesting but it doesn't really seem simpler, and IMO is potentially harder to understand. Similarly I don't think we want to get into all permutations of map/filter/remove
and ->/->>
. That said, we're open to ideas :).
Sounds good to me, thanks