This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-10-23
Channels
- # announcements (1)
- # architecture (20)
- # babashka (30)
- # beginners (79)
- # calva (27)
- # cider (8)
- # clj-kondo (1)
- # clojure (125)
- # clojure-australia (1)
- # clojure-berlin (4)
- # clojure-europe (62)
- # clojure-france (1)
- # clojure-italy (6)
- # clojure-nl (4)
- # clojure-uk (12)
- # clojuredesign-podcast (5)
- # clojurescript (28)
- # core-async (31)
- # cursive (14)
- # datomic (47)
- # defnpodcast (1)
- # emacs (7)
- # figwheel-main (2)
- # fulcro (10)
- # graalvm (1)
- # graphql (11)
- # jobs-discuss (8)
- # leiningen (2)
- # off-topic (23)
- # rdf (9)
- # re-frame (3)
- # reagent (1)
- # reitit (5)
- # reveal (12)
- # shadow-cljs (12)
- # spacemacs (1)
- # tools-deps (87)
- # vim (22)
- # xtdb (21)
God morgen. While working on deps-deploy
yesterday, I had to do some RTFSing in pomegranate
https://github.com/clj-commons/pomegranate/blob/master/src/main/clojure/cemerick/pomegranate/aether.clj and I'm struck by how different this code is from the code that I write on a day to day basis. From a call-site perspective, kw-args look realy nice:
(aether/deploy :artifact-map artifact-map
:repository repository
:coordinates coordinates)
But reading the code that gets called, not my cup of tea.I like kw-args when you need to do what they call “props drilling” in js react: passing down the same arguments deeply into the callstack and only change part of it.
But I’d rather use a map as an argument which makes everything simpler: (aether/deploy {:a… coordinates})
Yes, I totally see the use case for sending a bunch of stuff in one go, but as you, I prefer doing that in a map rather than with kw-args. Don't remember who's law it is, but basically if your function takes 9 arguments, you probably forgot a couple. Might have been Perlis
What's your preference:
(->> foos (map (fn [foo] [(bar foo) (baz foo)])) (into {}))
or
(reduce (fn [foos foo] (assoc foos (bar foo) (baz foo))) {} foos)
Yeah, didn't see the use for juxt
here as this was a simplification of a more complex example, but still... Maybe worth thinking how this could be solved with juxt
since it probably leads to smaller building blocks
@slipset but there's a law that when you have a chance to use juxt, you should take it. unlike macros
And in my example, it gets used to create map entries from vectors so we can stick them in a map
Oh, I just need to get this off my chest. Wouldn't it be nice if group-by
could get an extra arity so you could avoid doing somehting like:
(->> foos
(group-by :id)
(medley/map-vals whatever))
and rather do
(group-by :id whatever foos)
Basically this thing here https://github.com/plumatic/plumbing/blob/master/src/plumbing/core.cljx#L164
which is perhaps a bit more general as it applies a comped transducer to the groups (does the same for partition)
(def users [{:age :best, :name "erik"}, {:age :best, :name "dominic"}, {:age :too-old :name "bruce"])
(grouped-map :age :name users)
=> {:best ["erik", "dominic"], :too-old ["bruce"]}
@slipset This is just a matter of generalizing group-by right?
(defn group-by2
[f coll f-combine empty f-elt]
(persistent!
(reduce
(fn [ret x]
(let [k (f x)]
(assoc! ret k (f-combine (get ret k empty) (f-elt x)))))
(transient {}) coll)))
#'user/group-by2
user=> (group-by2 :age users conj [] :name)
{:best ["erik" "dominic"], :too-old ["bruce"]}
You could drop the empty
argument and have the combine function defaul accordingly.
(e.g. (fnil conj [])
in this case)
@ordnungswidrig on second thought no, because you can have nil vals:
user=> (get {:a nil} :a :foo)
nil
good point!
Otoh you can always thread the result of a simple group-by through a combine function
(->> x (group-by :some-key) (map (fn [[k vs] (reduce + vs)) (into {}))
(Somebody who knows about transducers can rewrite this to be performant I guess)
((But that’s not the point))
there's also index-by from medley which I sometimes need. which can also be written using the very decomplected group-by2:
(def users [{:age :best, :name "erik"}, {:age :best, :name "dominic"}, {:age :too-old :name "bruce"}])
(defn group-by2
[group-fn combine-fn empty elt-fn coll]
(persistent!
(reduce
(fn [ret x]
(let [k (group-fn x)]
(assoc! ret k (combine-fn (get ret k empty) (elt-fn x)))))
(transient {}) coll)))
(prn (group-by2 :age conj [] :name users))
;;=> {:best ["erik" "dominic"], :too-old ["bruce"]}
(defn index-by [f coll]
(group-by2 f (fn [_ x] x) nil identity coll))
(prn (index-by :id [{:id 1 :foo 2} {:id 2 :foo 2}]))
;;=> {1 {:id 1, :foo 2}, 2 {:id 2, :foo 2}}
(fn [_ x] x)
=> second
😛
actually true!