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. 🙂
Find a balance that works for you!
@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.(m/search [1 2 3 4 5 6]
(m/scan (m/pred number? !number))
!number)
;; =>
([1] [2] [3] [4] [5] [6])