-
Notifications
You must be signed in to change notification settings - Fork 67
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Suggested addition: update-items #63
Comments
What about a more general solution: (defn flip [f]
(fn [coll g & args]
(f #(apply g % args) coll))) It might need a better name, but it changes a collection function like ;; original
(map #(update % :price inc) items)
;; flipped
((flip mapv) items update :price inc) This allows us to write: (update m
:users
(flip mapv)
update :orders
(flip (comp set map))
update :items
(flip mapv)
update :price #(str "$" %)) And: (update m
:users
(flip (comp #(filterv (comp seq :orders) %) mapv))
update :orders
(flip (comp set map))
update :items
(flip filterv)
(comp even? :price)) |
I like it, |
I would recommend against the name |
What about |
|
After having thought about it a while, my current inclination is to use (defn tilt
"Converts a collection function of 2 arguments, such as map or filter, into a
function with an argument signature that can be used with update or swap!.
For a collection function collf, the expression ((tilt collf) coll f & args)
is equivalent to: (collf #(apply f % args) coll)."
[collf]
(fn [coll f & args]
(collf #(apply f % args) coll))) |
Just throwing in my 2c, I've been calling this fn (defn to->
"Adapt f to thread-first"
[x f & args]
(apply f (concat args (list x)))) It turns out that this fn is exactly equivalent to Accordingly, I also have a thread-last version: (defn to->>
"Adapt f to thread-last"
[f & args]
(let [x (last args)]
(apply f x (butlast args)))) |
Unless I'm mistaken, @maxrothman, your |
You're right, upon closer inspection, I wonder if there's a way to have the same fn/macro work for both Mostly I wanted to point out that adapting fns to thread-first/last is an adjacent problem, and that there might be utility in having the opposite-threading version as well. |
First off, this might be out of scope for the project, but I do think it is a powerful addition and still fits under pure, and general purpose. Second, I'm not sure if my implementation is the most performant, nor if the name is the best.
Rationale
It is very common to find highly nested data-structures.
This is why
get-in
,assoc-in
, andupdate-in
exist.Unfortunately, these fall apart if you need to process items of a collection within the structure. Even worse is if you have a multiple collections to in the tree. I believe this difficulty was a major motivator for large DSLs like meander or spectre.
I've been using this function for a number of years and find it invaluable when I know the shape of a data-structure but need to traverse collections and
update-in
is insufficient.Comparison
Here's an example, if I have a map with
users
, that haveorders
, that haveitems
, that each have aprice
Suppose you want to change all the item prices to strings with a dollar sign pre-pended. You'd need to do something like:
Writing this example out, I made a number of mistakes: I tried to nest function literals, I forgot to pass the coll to many of the
map
calls, I forgot that:orders
is supposed to be a set.Here's the signature for
update-items
, similar toupdate
butcoll-k
points at a collection anditem-update-fn
is applied to each item in the collection.Using this, our highly nested, tedious, and error-prone processing can flatten out completely.
POC Implementation
This could be written without
update-items*
but being able to pass themapping-fn
can be useful:The text was updated successfully, but these errors were encountered: