This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-04-04
Channels
- # announcements (28)
- # asami (12)
- # aws (3)
- # babashka (69)
- # babashka-sci-dev (34)
- # beginners (52)
- # biff (3)
- # calva (20)
- # clj-kondo (4)
- # cljsrn (4)
- # clojars (1)
- # clojure (90)
- # clojure-czech (2)
- # clojure-europe (33)
- # clojure-nl (11)
- # clojure-norway (35)
- # clojure-seattle (1)
- # clojure-uk (5)
- # clojurescript (87)
- # cursive (10)
- # datascript (5)
- # datomic (35)
- # defnpodcast (1)
- # emacs (8)
- # events (4)
- # fulcro (1)
- # google-cloud (2)
- # graphql (2)
- # hispano (2)
- # honeysql (5)
- # hoplon (2)
- # hugsql (1)
- # jobs (7)
- # kaocha (9)
- # lsp (102)
- # meander (13)
- # observability (7)
- # off-topic (56)
- # overtone (2)
- # pathom (47)
- # podcasts-discuss (1)
- # rdf (30)
- # reagent (16)
- # reitit (1)
- # releases (2)
- # remote-jobs (26)
- # rewrite-clj (10)
- # tools-deps (4)
- # vim (5)
- # vscode (4)
- # xtdb (41)
I'm a bit confused by this interaction:
(-> {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
(meander/search
(meander/scan [!sources {:c (meander/some _)}])
!sources))
the result I get back is ([:a] [:b])
but I would have expected ([:a :b])
. I'm tring to find all map keys that contain :c
in the submap.
edit: I get why this happens: each search is a separate search, that only finds one source. But how could I find them all?(m/find {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
(m/gather [!sources {:c (m/some _)}])
!sources)
Thanks for the solution, gather
was the missing piece, wasn't aware it existed. I'll confess I still have a bit of difficulty in formulating the correct mental plan when I want to write something with meander. Case in point, the original problem I wanted to solve was turning:
{:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
into:
{:a {:c 1}
:b {:a 0.5}
:c {:a 0.5 :b 1}}
(which are two representation of a weighted graph: the first by outgoing edges, the second by incoming edges).
It's still unclear to me how to jump from this solution to the complete one:
I was trying something along the line of:
-> {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
(meander/find
(meander/gather [!sources {:c (meander/some !weights)}])
{:c [!sources !weights]}))
but I don't see how to interleave !sources
and weights
to make them a map (almost all the combinations I tried return nil
). Also, it doesn't seem possible to turn the key :c
above in a logical variable. What should I think when solving this problem with meander?(-> {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
(meander/find
(meander/gather [!sources {:c (meander/some !weights)}])
{:c (zipmap !sources !weights)}))
if only I could do this for each key. Maybe the solution is doing that step outside of meander?Re: thinking: The problem should be broken down into steps rather than trying to be solved with one rule:
;; Step 1.
(m/search {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
{?k {?sk ?sv}}
[[?sk ?k] ?sv])
;; =>
([[:b :a] 0.5]
[[:c :a] 0.5]
[[:c :b] 1]
[[:a :c] 1])
;; Step 2.
(reduce
(fn [m [path v]]
(assoc-in m path v))
{}
'([[:b :a] 0.5]
[[:c :a] 0.5]
[[:c :b] 1]
[[:a :c] 1]))
;; =>
{:a {:c 1}
:b {:a 0.5}
:c {:a 0.5 :b 1}}
ok, I'm glad that's the solution, as I did something similar in two steps (but didn't have the idea of grouping the keys to use them with assoc-in
; brilliant!)
Thank you! 🙂
OK. Sorry, I made a small mistake in the previous post. Here is the corrected m/rewrite
version:
(m/rewrite [{:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
{}]
[{?k {?sk ?sv & ?m-k} & ?m-in}
{?sk ?m-ko & ?m-out}]
(m/cata [{?k ?m-k & ?m-in}
{?sk {?k ?sv & ?m-ko} & ?m-out}])
[{?k {?sk ?sv & ?m-k} & ?m-in}
?m-out]
(m/cata [{?k ?m-k & ?m-in}
{?sk {?k ?sv} & ?m-out}])
[_ ?m-out]
?m-out)
;; =>
{:b {:a 0.5}, :c {:b 1, :a 0.5}, :a {:c 1}}
Using a step-wise approach:
(let [step (fn [pair]
(m/rewrite pair
[{?k {?sk ?sv & ?m-k} & ?m-in}
{?sk ?m-ko & ?m-out}]
[{?k ?m-k & ?m-in}
{?sk {?k ?sv & ?m-ko} & ?m-out}]
[{?k {?sk ?sv & ?m-k} & ?m-in}
?m-out]
[{?k ?m-k & ?m-in}
{?sk {?k ?sv} & ?m-out}]
[_ ?m-out]
?m-out))
init [{:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
{}]]
(-> init
step ;; => [{:b {:c 1}, :c {:a 1}, :a {:c 0.5}} {:b {:a 0.5}}]
step ;; => [{:c {:a 1}, :a {:c 0.5}, :b {}} {:b {:a 0.5}, :c {:b 1}}]
step ;; => [{:c {:a 1}, :b {}, :a {}} {:b {:a 0.5}, :c {:b 1, :a 0.5}}]
step ;; => [{:b {}, :a {}, :c {}} {:b {:a 0.5}, :c {:b 1, :a 0.5}, :a {:c 1}}]
step))
;; =>
{:b {:c 0.5, :a 0.5},
:c {:a 0.5},
:a {:c 1}}
The second case can be handled in the first case with m/or
and m/let
:
(m/rewrite [{:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
{}]
[{?k {?sk ?sv & ?m-k} & ?m-in}
(m/or {?sk ?m-ko & ?m-out}
(m/let [?m-ko {}] ?m-out))]
(m/cata [{?k ?m-k & ?m-in}
{?sk {?k ?sv & ?m-ko} & ?m-out}])
[_ ?m-out]
?m-out)
;; =>
{:b {:a 0.5}, :a {:c 1}, :c {:b 1, :a 0.5}}
This is to demonstrate that you can do this kind of thing but not necessarily that you should do this kind of thing. 🙂
@meditans search
is for finding all possible solutions, find
is for finding one (or none). The reason the search
returns is ([:a] [:b])
is because it there are two solutions and !sources
is a singleton vector where !sources
matched once for each of the solutions. m/scan
is sugar for
(m/seqable & _ <patterns ...> & _)
The & _
on either side of <patterns ...>
is the flexible, ambiguous space and <patterns ...>
is what is being matched.