meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
prnc 2021-02-24T14:59:54.019300Z

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.

prnc 2021-02-24T15:54:18.021500Z

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?

jimmy 2021-02-24T16:11:14.021800Z

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
jimmy 2021-02-24T16:12:09.022200Z

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
prnc 2021-02-24T16:15:53.022400Z

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

prnc 2021-02-24T16:16:19.022600Z

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

prnc 2021-02-24T16:16:58.022800Z

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

prnc 2021-02-24T16:17:16.023Z

second returns {:f bar, :t nil}

prnc 2021-02-24T16:31:06.023400Z

looks like I can just use m/or here?

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

prnc 2021-02-24T16:31:15.023600Z

nice thanks!

jimmy 2021-02-24T16:36:17.023800Z

Yep, or is the answer

prnc 2021-02-24T16:37:15.024Z

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 😜

jimmy 2021-02-24T16:39:49.024200Z

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.

prnc 2021-02-24T16:43:28.024400Z

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

phronmophobic 2021-02-24T21:42:16.025500Z

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]

noprompt 2021-02-24T22:26:00.025700Z

You could also try

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

👍 1
phronmophobic 2021-02-24T22:33:30.026200Z

ok, that works

noprompt 2021-02-24T22:34:55.026400Z

LMK if you run into any problems.

1
noprompt 2021-02-24T23:32:32.027400Z

https://clojars.org/meander/epsilon

noprompt 2021-02-24T23:32:41.027700Z

New release available folks.

noprompt 2021-02-24T23:34:15.029300Z

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