meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
ikrimael 2020-07-08T00:54:47.489300Z

I marked questions/requests for feedback with QUESTION tag inline

noprompt 2020-07-08T00:55:43.490Z

I saw that. 🙂

noprompt 2020-07-08T00:56:00.490700Z

This is great by the way. 👍

ikrimael 2020-07-08T00:56:30.491800Z

meta-question: ofc lmk if there's other changes to make it easier to review. I had a bunch of examples and scrapped them once I realized I could answer all of them by looking at the tests file

ikrimael 2020-07-08T00:56:58.492700Z

ofc, i'll be going back to add them; was just way off in that first attempt

noprompt 2020-07-08T00:57:38.493700Z

Ha! It’s funny because I’ve often thought it might be more accessible/friendly to extract some of the test examples into the cookbook i.e. the fib-test stuff.

ikrimael 2020-07-08T00:58:11.494700Z

heh, fwiw, they were super helpful! also made me realize the docs didn't include the full api

noprompt 2020-07-08T00:59:03.496300Z

Yeah, there’s a lot there and I generally don’t follow implementation updates, etc. with doc updates (I should, I know).

ikrimael 2020-07-08T01:00:06.497300Z

meta-comment: i think also helpful is more philosophical comment/feedback of "should meander even be used for this scenario?"

noprompt 2020-07-08T01:02:17.499800Z

Definitely. Honestly, we have made a good faith effort to do that here.

ikrimael 2020-07-08T01:02:18Z

I often find myself looking at my meander rewrite and thinking I've made it more obtuse. (Ofc as one who's learning both clojure + meander, I put weight = near 0 on my thoughts at this point)

noprompt 2020-07-08T01:02:40.000500Z

A meander group-by often comes up and the recommendation has always been to just use group-by.

ikrimael 2020-07-08T01:03:28.000900Z

ah interesting; i'll have to look that up

ikrimael 2020-07-08T01:04:36.002700Z

i've also opted to put the different iterations of my meander attempts in the cookbook (both for future me's sake and learning value); ofc feel free to scrub them or maybe move them to a tutorial

noprompt 2020-07-08T01:07:09.004400Z

Jimmy does that to great effect in some of his posts and I think it’s a nice way to guide someone from one place to the next.

noprompt 2020-07-08T01:07:51.005200Z

With rewrite you can do the (m/app #(->OppathSeg :seg-attr %1) !seg) on the right side.

noprompt 2020-07-08T01:08:48.006100Z

Someone I work with isn’t really a fan of m/app on the left side.

noprompt 2020-07-08T01:09:53.007300Z

If I can defer m/app to the right side, I do.

ikrimael 2020-07-08T01:10:32.008Z

i'd say i'm in that camp too; i couldn't figure out how to carry the "patteern match state" though to the right side

ikrimael 2020-07-08T01:11:16.008600Z

i.e. I find myself wanting to do this alot

token ::= (:arg-in|:arg-out) ?argname
    pseudocode-result:: (str (emit-in ?arg-attr)|emit-out :arg-attr) ?argname)

noprompt 2020-07-08T01:11:51.009400Z

Strings are on the list of things match/build.

noprompt 2020-07-08T01:12:44.010600Z

I’ve been catching up on some research and experimenting with how to model, compile, interpret, etc.

ikrimael 2020-07-08T01:13:24.011900Z

sans strings, would it be possible to do that? I keep reaching basically for the rhs to apply different functions based on the pattern matched

noprompt 2020-07-08T01:13:24.012Z

Another thing that’s on the list is a way to aggregate.

noprompt 2020-07-08T01:13:44.012300Z

Possible to pattern match on strings?

ikrimael 2020-07-08T01:14:17.012900Z

ah, i mean excluding the string case

noprompt 2020-07-08T01:15:01.013700Z

Oh are you asking if the thing matches bind it to a variable?

ikrimael 2020-07-08T01:15:31.014600Z

ie in my example, i pattern match an xpath segment (ignore that it's a string). I want to apply a transform to said xpath segment depending on the type of xpath segment

noprompt 2020-07-08T01:16:09.014900Z

Use two memory variables?

noprompt 2020-07-08T01:16:44.015800Z

!seg-attrs , !seg-chlds and then apply the transforms on the right.

ikrimael 2020-07-08T01:16:46.016Z

oh; can I use m/or on the rhs in substitutions?

noprompt 2020-07-08T01:17:19.016500Z

You can’t use m/or on the right side yet.

noprompt 2020-07-08T01:17:32.017Z

But memory variables are always initialized to the empty vector at a minimum.

noprompt 2020-07-08T01:18:18.018400Z

[(m/app f !seg-attrs) ... (m/app g !seg-chlds) ...]

noprompt 2020-07-08T01:18:54.019Z

FYI I gotta step away for a bit. Should be back in a couple hours.

ikrimael 2020-07-08T01:19:05.019300Z

sure, np! let me play with that a little

ikrimael 2020-07-08T01:34:19.020500Z

ah couldn't get it to work still. Here's a simplified snippet showcasing actual vs desired output

(defn f [xseg] {:kind :seg-attr :val xseg})
(defn g [xseg] {:kind :seg-chld :val xseg})
(m/rewrite ["oppas" "obj1" "@attr1" "@attr2" "obj2"]
  (m/with [%segattr (m/pred #(= (first %1) \@)    !seg-attrs)
           %segobj  (m/pred #(not= (first %1) \@) !seg-chlds)]
          [(m/re #"obj|oppas|dc" ?ns) . (m/or %segobj %segattr) ...])
  {:ns    (keyword ?ns)
   :xsegs [(m/app f !seg-attrs) ... (m/app g !seg-chlds) ...]}
)
;; INCORRECT: => 
{:ns (keyword "oppas")
 :xsegs
 [{:kind :seg-attr, :val "@attr1"}
  {:kind :seg-attr, :val "@attr2"}
  {:kind :seg-chld, :val "obj1"}
  {:kind :seg-chld, :val "obj2"}]}

;; CORRECT =>
{:ns (keyword "oppas")
 :xsegs
 [{:kind :seg-chld, :val "obj1"}
  {:kind :seg-attr, :val "@attr1"}
  {:kind :seg-attr, :val "@attr2"}
  {:kind :seg-chld, :val "obj2"}]}

noprompt 2020-07-08T03:37:23.022900Z

Gotcha. There are two approaches you could apply here. The first one uses a helper to construct the xseg:

(defn make-xseg [val]
  (m/rewrite val
    (m/re #"@.*" ?val)
    {:kind :seg-attr :val ?val}

    (m/re #"[^@].*" ?val)
    {:kind :seg-chld :val ?val}

    ?val
    {:kind :unknown :val ?val}))


(m/rewrite ["oppas" "obj1" "@attr1" "@attr2" "obj2"]
  [(m/re #"obj|oppas|dc" ?ns) . !segs ...]
  {:ns (m/keyword ?ns)
   :xsegs [(m/app make-xseg !segs) ...]})
;; =>
{:ns :oppas,
 :xsegs
 [{:kind :seg-chld, :val "obj1"}
  {:kind :seg-attr, :val "@attr1"}
  {:kind :seg-attr, :val "@attr2"}
  {:kind :seg-chld, :val "obj2"}]}
The second uses m/cata on the left or right side:
;; Left side
(m/rewrite ["oppas" "obj1" "@attr1" "@attr2" "obj2"]
  [(m/re #"obj|oppas|dc" ?ns) . (m/cata !segs) ...]
  {:ns (m/keyword ?ns)
   :xsegs [!segs ...]}

  (m/re #"@.*" ?val)
  {:kind :seg-attr :val ?val}

  (m/re #"[^@].*" ?val)
  {:kind :seg-chld :val ?val}

  ?val
  {:kind :unknown :val ?val})

;; Right side
(m/rewrite ["oppas" "obj1" "@attr1" "@attr2" "obj2"]
  [(m/re #"obj|oppas|dc" ?ns) . !segs ...]
  {:ns (m/keyword ?ns)
   :xsegs [(m/cata !segs) ...]}

  (m/re #"@.*" ?val)
  {:kind :seg-attr :val ?val}

  (m/re #"[^@].*" ?val)
  {:kind :seg-chld :val ?val}

  ?val
  {:kind :unknown :val ?val})

👌 1
markaddleman 2020-07-08T04:17:21.024800Z

I hadn't thought about using cata on the right side before. In this example, it doesn't look like there's much advantage. Offhand, can you think of a situation where cata on the rhs is meaningfully different/important?

JAtkins 2020-07-08T04:37:59.026800Z

@e749 Thank you for adding more examples! I have tried a couple times to pick up meander, always got stuck on something. Hoping to make a push in 2-3 weeks to start using it alot more. (should go without saying thanks to Jole and the other authors too though 🙂)

noprompt 2020-07-08T04:38:53.027900Z

@markaddleman Cata on the right side can be used to construct a value to be recursively rewritten. It’s the dual of the left.

markaddleman 2020-07-08T04:39:36.028Z

Ah, of course. Thanks

noprompt 2020-07-08T04:40:32.028200Z

(m/rewrite ["oppas" "obj1" "@attr1" "@attr2" "obj2"]
  [(m/re #"obj|oppas|dc" ?ns) . !segs ...]
  {:ns (m/keyword ?ns)
   :xsegs [(m/cata ($EXAMPLE !segs)) ...]}

  ($EXAMPLE (m/re #"@.*" ?val))
  {:kind :seg-attr :val ?val}

  ($EXAMPLE (m/re #"[^@].*" ?val))

  {:kind :seg-chld :val ?val}

  ($EXAMPLE ?val)
  {:kind :unknown :val ?val})
;; =>
{:ns :oppas,
 :xsegs
 [{:kind :seg-chld, :val "obj1"}
  {:kind :seg-attr, :val "@attr1"}
  {:kind :seg-attr, :val "@attr2"}
  {:kind :seg-chld, :val "obj2"}]}

ikrimael 2020-07-08T04:41:24.028400Z

sure np! feel free to add feedback to the draft PRs

ikrimael 2020-07-08T04:42:35.028700Z

brilliant; both left side/right side with m/cata feel clean and easily grokkable for future me

noprompt 2020-07-08T04:43:32.028800Z

You can do some exotic/interesting kinds of things with this.

noprompt 2020-07-08T04:45:03.029Z

@jatkin Reach out when you get stuck. If I can help, I will. 🙂

JAtkins 2020-07-08T04:54:04.029200Z

Thanks, I will probably end up doing so 🙂. I'm trying to set myself up for success in https://github.com/JJ-Atkinson/Fisher project, and I think meander might be quite helpful for sections.

ikrimael 2020-07-08T04:56:25.029700Z

@jatkin hah! exactly what i'm using it (albeit targetted towards C/C++)

JAtkins 2020-07-08T04:57:32.029900Z

How so?

ikrimael 2020-07-08T05:00:16.030100Z

parse decorated c/c++ => highlevel IR => clojure does term rewriting/inline expansion/etc => codegen c/c++ & UI bindings => JIT back into the app/editor

💯 1
ikrimael 2020-07-08T05:01:07.030300Z

it's more or less the lighttable dream but with c/c++ target & gamedev focus

JAtkins 2020-07-08T05:03:06.030500Z

Gacha. Sounds neat. It is/was a great piece of software.