Fork me on GitHub
#meander
<
2021-02-24
>
prnc14:02:54

Hi! I’m just having quite pleasant first encounter with meander and I was wondering what’s the best way of searching through a tree shaped structures, e.g.

{:name ,,,
   :id ,,,
   :age ,,,
   :children [{:name ,,, :id ,,, :age ,,, :children ,,,} ,,,]}
  
Say I’m using match defining my transformation for the top level and want to recurse on optional children.

jimmy16:02:14

For tree structures it really depends on what you are trying to do more concretely. Cata is a super useful tool here (think of it like the recur of meander).

(m/rewrite 
  {:name "jimmy"
   :id 11
   :age 29
   :children [{:name "lemon" :age 4 :type :dog}]}

  
  {:name ?name
   :children (m/some ?children)}

  {:name ?name
   :kids (m/cata ?children)}

  {:name ?name}
  {:name ?name}

  [!xs ...]
  [(m/cata !xs) ...])

;; => {:name "jimmy", :kids [{:name "lemon"}]}



(m/rewrite 
  {:name "jimmy"
   :id 11
   :age 29
   :children [{:name "lemon" :age 4 :type :dog}]}

  {:name !names
   :children (m/or [(m/cata [!names ...]) ...] nil)}
  [!names ...])

;; => ["jimmy" "lemon"]
Strategies are also useful. WIth can help. But also don’t be afraid to just start with a clojure.walk and add meander into that.

👍 1
prnc16:02:15

Nice! thanks! I was looking at cata but wasn’t sure cause it feels that I need to specify the case for with children and without children separately? Even though it’s the same case i.e. they would have everything in common except for that one thing (missing/optional :children key), so I would be repeating “the same” transformation twice? Not sure if this description makes sense to you, need to dive deeper into the lingo around this, to ask better questions 😜

jimmy16:02:49

Yeah, sometimes you have to repeat the same transformation twice. Sometimes you can use or. You can also pull out some of that using with if it becomes too repetitive. But in general, we have found being explicit in handling those cases separately can be nice.

prnc16:02:28

alright! thanks again 🙂 need to play around a bit more to potentially come back with more (better) questions 🙂

prnc15:02:18

also is using memory variables making keys in a map non-optional? as in (playing w/ twitter api) …

(m/match tweet
     {::id ?id
      ::author-id ?aid
      ::text ?text
      ::entities {::mentions    [!ms ...]
                  ::annotations [!as ...]}}
<do stuff>)
if some of the tweets don’t have entities they won’t match?

jimmy16:02:09

Keys in maps are always non-optional. (I am voting to change this behavior in zeta). But you can make them required by doing (m/some ?id).

👍 1
prnc16:02:53

Thanks! So there is for example no way for the pattern above to match both tweets with ::entities and with them?

prnc16:02:19

The behaviour seems to be different between:

(m/match {:foo 'bar}
    {:foo ?f
     :this [!t ...]}
    {:f ?f
     :t !t})

  (m/match {:foo 'bar}
    {:foo ?f
     :this ?t}
    {:f ?f
     :t ?t})

prnc16:02:58

first snippet with memory variable !t throws: non exhaustive…

prnc16:02:16

second returns {:f bar, :t nil}

prnc16:02:06

looks like I can just use m/or here?

(m/match {:foo 'bar}
    {:foo ?f
     :this (m/or [!t ...] nil)}
    {:f ?f
     :t !t})

prnc16:02:15

nice thanks!

jimmy16:02:17

Yep, or is the answer

phronmophobic21:02:16

I'm using meander for the first time and it's working great 😄. Most things have been pretty straightforward, but there's one example where I was wondering if there was a more idiomatic approach. I'm parsing a hairy xml response that essentially returns an unordered list of tagged elements. I'm using m/app to turn the list into a map so that I can grab any subset of items that match. Is there a better way? Simplified example below:

(m/find [{:type :foo
          :a 1}
         {:type :baz
          :c 3}
         {:type :bar
          :b 2}
         ]
  (m/app #(zipmap (range) %)
         {_c {:type :baz
              :c ?c}
          _a {:type :foo
              :a ?a}
          _b {:type :bar
              :b ?b}
          })
  [?a ?b ?c])
;; [1 2 3]

noprompt22:02:00

You could also try

(m/app set
  #{{:type :baz, :c ?c}
    {:type :foo, :a ?a}
    {:type :bar, :b ?b}})

👍 1
phronmophobic22:02:30

ok, that works

noprompt22:02:55

LMK if you run into any problems.

thanks3 1
noprompt23:02:41

New release available folks.

noprompt23:02:15

This one fixes a compilation bug where qualified symbols were being used for let bindings (thanks @jimmy) and another one with map compilation (thanks @ericgierach and @mdp for the report).

🎉 5