This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-02-12
Channels
- # announcements (32)
- # aws (7)
- # babashka (2)
- # babashka-sci-dev (1)
- # beginners (25)
- # biff (1)
- # calva (1)
- # cider (27)
- # clj-kondo (15)
- # clojure (24)
- # clojure-berlin (1)
- # clojure-czech (4)
- # conjure (9)
- # cursive (7)
- # datalevin (1)
- # emacs (19)
- # events (1)
- # gratitude (1)
- # integrant (1)
- # introduce-yourself (2)
- # java (4)
- # meander (17)
- # membrane (4)
- # podcasts-discuss (1)
- # releases (1)
- # remote-jobs (2)
- # ring-swagger (8)
- # shadow-cljs (14)
- # testing (1)
- # tools-build (5)
- # tools-deps (3)
Wondering how I can do the following w/out a group-by
:
(let [coll [{:foo "a" :bar "b" :baz 123}
{:foo "x" :bar "y" :baz 666}
{:foo "a" :bar "b" :baz 987}]]
(m/search (group-by (juxt :foo :bar) coll)
(m/scan [[?foo ?bar] [{:baz !baz} ...]])
{:foo ?foo
:bar ?bar
:children (for [v !baz]
{:baz v})}))
;; =>
({:foo "a", :bar "b", :children ({:baz 123} {:baz 987})}
{:foo "x", :bar "y", :children ({:baz 666})})
I figure it’d need some way of remembering the different foo
& bar
values and baz
associated w/ them…keep in mind that the maps w/ same foo
/`bar` pairs aren’t necessarily in order.This comes up from time to time (group-by) which currently has no clean solution but will (hopefully) later this year. For these situations group-by
is what I typically recommend because the alternative is not always that great.
(let [coll [{:foo "a" :bar "b" :baz 123}
{:foo "x" :bar "y" :baz 666}
{:foo "a" :bar "b" :baz 987}]]
(m/rewrite coll
(m/with [%it {:foo ?foo, :bar ?bar, :baz !baz}]
[%it . (m/or %it !not-it) ...])
({:foo ?foo, :bar ?bar, :children [!baz ...]}
& (m/cata [!not-it ...]))
_
()))
Here the issue is performance due to nodes being visited again and again. We can try a different approach.
(let [coll [{:foo "a" :bar "b" :baz 123}
{:foo "x" :bar "y" :baz 666}
{:foo "a" :bar "b" :baz 987}]]
(m/rewrite [coll {}]
[[{:foo ?foo, :bar ?bar, :baz ?baz} & ?rest]
(m/and ?index
(m/or {[?foo ?bar] ?children}
(m/let [?children []])))]
(m/cata [?rest {[?foo ?bar] [?baz & ?children] & ?index}])
[[] (m/map-of [!foo !bar] !children)]
({:foo !foo, :bar !bar, :children !children} ...)))
This approach is, eh, not terribly attractive but I think it should be more performant than the other.Either way, I think group-by
is much easier to wield and has more utility than what Meander can offer at the moment (which is okay!).
Still, I think its a fun exercise to write out the semantically equivalent rules of a particular group by as practice.
Hey. This seems simple enough but it’s been hours (I don’t want to admit how many) and I haven’t got a solution. I want to turn this
[[:<>]
'four
[:<> 'one ['three [:<> 'two]]]
[:<> [:<> 'three]]]
into this
['four 'one ['three 'two] 'three]
I’m trying to splat any vector that starts with that keyword into the parent vector.This comes up because I have multiple things on the rhs of my rewrite rule but I don’t want it in a vector in the parent vector. e.g.
{:node-type :module
:body [(m/app f !body) ...]}
[:<> (ns file-name-maybe)
& [!body ...]]
{:node-type :name
:id (m/app keb-sym ?id)}
?id
The best idea I’ve had so far is to denote the ones that I want to flatten and flatten them after.Oh. This is interesting. I kept trying things that worked top down but then I’d skip collapsing a level. I needed something that worked botom up.
(defn splat-fragments
[xs]
(cond
(sequential? xs) (->> (map splat-fragments xs)
(map
#(if (and (sequential? %) (= :<> (first %)))
(rest %)
[%]))
(apply concat))
:else xs))
(let [input [[:<>]
'four
[:<> 'one ['three [:<> 'two]]]
[:<> [:<> 'three]]]]
(m/rewrite input
(m/with [%splice (m/or [:<> . (m/or %splice %node) ...] %node)
%node (m/cata !node)]
[%splice ...])
[!node ...]
?x ?x))
;; =>
[four one [three two] three]
This might be a tad clearer?
(m/rewrite input
(m/with [%splice [:<> . %main ...]
%node (m/cata !node)
%main (m/or %splice %node)]
[%main ...])
[!node ...]
?x ?x)