Fork me on GitHub
#meander
<
2022-04-04
>
Carlo11:04:46

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?

noprompt15:04:30

``````(m/find {:a {:b 0.5 :c 0.5}
:b {:c 1}
:c {:a 1}}
(m/gather [!sources {:c (m/some _)}])
!sources)``````

❤️ 1
Carlo18:04:03

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?

Carlo18:04:08

``````(-> {: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?

noprompt19:04:30

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}}``````

🙌 1
Carlo19:04:40

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! 🙂

noprompt19:04:17

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}}``````

noprompt19:04:02

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}}``````

noprompt19:04:09

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}}``````

noprompt19:04:45

This is to demonstrate that you can do this kind of thing but not necessarily that you should do this kind of thing. 🙂

noprompt19:04:20

Find a balance that works for you!

noprompt15:04:25

@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.

🙌 1
noprompt16:04:00

``````(m/search [1 2 3 4 5 6]
(m/scan (m/pred number? !number))
!number)
;; =>
(     )``````