meander 2021-09-10

(m/rewrites {:x {:y [:a :b :c]
                         :q [:a :b :c]}}
          {!xs {!ys (m/scan :b)}}
          [[!xs !ys] ...])
Is there any way to do this without using rewriteS but with just simple rewrite?

I think. Lemme try…

Why does it work with r1 and not with r2?

Sorry, I'm also having trouble creating a more minimal example. I feel in over my head.

There are a multiple keys in map r2 :active and scan can't handle it

Unfortunately I'm writing from my phone so I can't help you right now

No trouble. That's already very helpful. Thank you!

(let [r1 [[0 {:active {:a {:ids [{:business "123"}]}}}]
          [1 {:active {:d {:ids [{:business "567"}]}}}]]
      r2 [[0 {:active {:a {:ids [{:business "123"}]}
                       :b {:ids [{:business "234"}]}}}]
          [1 {:active {:d {:ids [{:business "567"}]}
                       :c {:ids [{:business "678"}]}}}]]
      f (fn [arg]
          (m/rewrite arg
            [[(m/and !xs !ys) {:active (m/map-of _ {:ids [{:business !ids}]})}] ...]
            [[[!xs !ids] [!ys !ids] ...]]))]
  (f r1)                                ;; [[0 "123"] [1 "567"]]
  (f r2)                                ;; [[0 "123"] [0 "234"] [1 "567"] [1 "678"]]
  )

Surely it can be done more simply

Hey. I figured some things out. First I got the answer I wanted from this smaller example:

(let [r2 [{:a [{:word "123"}
               {:word "abc"}]
           :b [{:word "234"}
               {:word "bcd"}]}]
      f (fn [arg]
          (m/find
            arg
            (m/gather (m/map-of _ (m/gather {:word !a})))
            !a))]
  (f r2))
  ;; => ["123" "abc" "234" "bcd"]
But it didn’t seem like I was doing this correctly since I think I should be able to search with a logic var instead of using a memory var like that. The example for scan gave me the idea to treat a map as a seq of MapEntry.
(m/search {:x 1 :y 2 :z 3}
  (m/scan [?a ?b])
  {?b ?a})
;; => ({1 :x} {2 :y} {3 :z})
So then I got this working code:
(let [r2 [{:a [{:word "123"}
               {:word "abc"}]
           :b [{:word "234"}
               {:word "bcd"}]}]
      f (fn [arg]
          (m/search
            arg
            (m/scan (m/scan [_ (m/scan {:word ?a})]))
            ?a))]
  (f r2))

  ;; => ("123" "abc" "234" "bcd")
Going back to an example of my actual problem:
(let [r2 [[0 {:active {:a {:ids [{:business "123"}
                                 {:business "aha"}]}
                       :b {:ids [{:business "234"}]}}}]
          [1 {:active {:d {:ids [{:business "567"}]}
                       :c {:ids [{:business "678"}]}}}]]
      f (fn [arg]
          (m/search
            arg
            (m/scan [?t {:active (m/scan [_ {:ids [{:business !a} ...]}])}])
            [?t !a]))]

  (f r2))
;; => ([0 ["123" "aha"]] [0 ["234"]] [1 ["567"]] [1 ["678"]])
I actually want to get a result like ([0 [“123” “aha” “234”]] [1 [“567" “678”]]) but I haven’t figured it out yet. Thank you all of you for making such a sick library and for the great support.

🎉 1

@huxley Thanks for the working example. I didn’t know about map-of until I saw you use it. After that, I cloned the repo and poked around reading through some of the docstrings. Ultimately, I don’t think I want to use and since I don’t know how many things I’ll have there; I could have made a better question than to just ask why it was broken, haha. Thanks again.

Wanted to share something cool and ask if you think I made any mistakes or it could be improved - beta reduction of tools.analyzer ast node:

(m/rewrite
    node
    {:op :invoke
     :args [!args ..?n]
     :fn {:op :fn
          :methods
          [{:fixed-arity ?n
            :variadic? false
            :form _ :arglist _ :tag _ :o-tag _ ;; rudely ignore
            :params
            [{:local _ :arg-id _
              & !params} ...]
            :body ?body}
           ..1]} ;; there can be only one!
     & ?rest}
    {:op :let
     :children [:bindings :body]
     :bindings
     [{:init !args
       :local :let
       :children [:init]
       & !params} ...]
     :body ?body})

I don't know what it does but it looks cool

_ can be omitted if they are not for readability

whereas, if these are the required things that should be there, then it's a good idea to wrap in (m/some)

It's a poor man's dissoc but you're right, I should rewrite it

what it does: ((fn [x] B) E) -> (let [x E] B)

Awesome! This is definitely one of the use cases I was designing for. 🙂

Success :)

Is it possible to perform a recursive search and substitution inside a bound variable?

OPened a discussion for both

cata still assumes I know the shape of the input (sort of). In the case where I don't want to specify all the possible patterns, is there a generic walk?

Try strategy namespace

Probably bottom-up is what you're looking for

I'd still have to specify all the patterns I want to search over 😞

Ben, are you able to layout in more detail what your idea/goal is? I’m not sure I totally follow.

Sure, I'm trying to implement optimization passes on tools.analyzer output. Beta reduction, copy and constant propagation

Cool. I follow this. I was looking for an example/sketch (could be contrived) of the problem and what you would like the solution to look like/the result, etc.

We do need a more general walking mechanism that isn’t strategy based. I have some ideas about that but none that I can invest time in right now.

One of the things that I’ve done in the past is write rules like this

(m/rewrite form
  [::special def ?tail]
  {:type :def  ,,,}

  ((m/pred special-symbol? ?symbol) & tail)
  (m/cata [::special ?symbol ?tail]))
essentially emulating a function/function call inside the system.

You could write a HOF which returns a walker

Bottom up and top down are a special case of post/pre walk derived from it

I wanted to mention earlier, Github discussions are available too if you want to jot down something a bit more long form that lays out the full scope of the problem.

Probably will, thank you 🙂

Oh nice. I was upset that slack limits the conversation history since I’d like to dig through the history for more examples.

Please post there. And, if you do, share the link here as well.

Honestly, I should probably do that too.

You could probably make half a cookbook by scraping the history of this channel on the log. zulip?

> Hey! I hope you’re having a great day. This sentence. 😄

Also the title. High marks. 100%

regarding the learning curve, I don't think there is anything that can be done about it

meander is simple but not easy

some concepts like cata or with just have to pop in our head

Is there anything I can read which would help me understand cata? Sometimes I find original papers on subjects make it click for me. Did so for HAMTs and CSP

cata is simply recursion

of the non-obvious things that came out of using cata was discovering that you can put the processed data into a vector, where the first element is whatever tells you what to do with it

I understand all of these words, but have no way to translate them to actionable knowledge yet. Maybe 11pm is not the time

I guess it just requires some practice

I would start by looking at all the examples that are in the meander repo. Reading through all the tests also gave me a lot.

I read the cata tests several times. The trivial cases made sense but didn't click for me yet. No worries, I shall bang my head against that wall until it breaks

I've been through it, and after some head-banging, the tinnitus even stops

😆 1

in general I appreciate your work, e.g. on malli, a lot can be learned by reading the code

I think you have a perversion to numbers and like to speed up other people's code 🙃

Ha, guilty

And thank you 😃

you'll probably find something to do once you get into the meander code

Besides, I want to use meander to speed up other code. All the code, if possible 🙂

well, that's what I'm currently trying to do

Speed up meander or use meander to write a compiler?

> and it's addictive Absolutely

numbers go woosh

dopamine over 9000!!!

have you applied meander to tools.analyzer ast?

code in meander can be fully declarative, imho it is often much more readable than pure clojure, moreover it is easy to come back to, because, omits some concepts like cata, it is clear and understandable

for now, I'm learning meander mostly by writing doxa and poking around in meander itself

it seems like a very good fit. There are some Haskell papers which are relevant

wait, because I don't think I quite caught on before

You literally want to use meander to rewrite other people's code

An alternative compiler

thanks 😄

and the video linked in the discussion

it's a bit beyond my homegrown programming knowledge, but I'm happy to watch

I did not study computer science 🤷

If you can get meander, you can get Core

Besides Big Lambda type constructors don't ask me about those types are hard

haskel sounds like something you need a PhD to understand

Yes, which is why I'm not trying to understand Haskell, but the intermediate language and how they transform it for optimizations

👍 1

Meanwhile, I've got to go. Thanks for the chat.

sleep time for me 🌃

Core is cool. 😎

I wish I could take a sabbatical to work on this

Haha, thanks. I was feeling punchy after punching away at the same problem all day.

New meaning of "using X in anger"?

🤣 1

Ah, yeah, that can be frustrating. And I know there is a learning curve. Buuuut, hopefully, we can help. 🙂

One day I'll understand m/cata then I'll be able to just communicate telepathically or something

It seems like the learning curve is steeper than most new things that I encounter while programming but the payoff also seems much greater than the usual new thing. So much so that the ratio of cost to benefit weighs heavily in favor of learning and using it. It’s existence and this community are also gifts so I can’t begin to be critical. I’m not actually angry; I’m just playing it up for the humor. 🙂

> the learning curve is steeper … the ratio of cost to benefit weighs heavily in favor of learning and using it This is a perspective I think others in the channel share. Improving the overall experience and reducing the learning curve/providing help are priorities. For me, the criticism is inspiring actually, I’ve just had a rough time the past year dealing with burn out from software, and $pandemic_related_reasons .

But I will say, this channel is awesome. I’m really proud of the folks in here. People are helpful and courteous. “No stupid questions” kind of attitude. 🙂

This channel has kept me going!

Also, I will try and fill in some explaining on my replies to your question.