meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
noprompt 2020-06-16T01:13:51.409100Z

Some good news: The next release of Meander will be generally faster! The work I’ve been doing to put optimizations behind flags has lead me to address a number of related gaps in the current implementation. The match compiler (e.g. the macro expansion), and map and set pattern matching have received some much needed attention over the past few weeks. I’m really excited to get these updates out.

noprompt 2020-06-16T01:16:45.411Z

To throw some numbers out, currently on my machine it takes somewhere between 900 and 1000ms to run the Clojure test suite. On the epsilon-compiler-flags branch the same test suite runs in between 580 and 650ms. Thats a significant improvement.

5🦜
noprompt 2020-06-16T01:27:38.412400Z

I think this is post compile e.g. post macro expansion but I don’t know for certain. If anyone knows let me know because I’m too lazy to look at the moment. 🙂

respatialized 2020-06-16T17:56:10.418700Z

hi there! I have a question about some memory variable behavior that I find a little confusing. I'm trying to pattern match by a predicate and then put all matches into a hiccup data structure. Here's a basic example, adapted from the documentation:

(let [!s ["a" "b" "c"]] (m/subst [:ul . [:li !s] ...]))
=> [:ul [:li "a"] [:li "b"] [:li "c"]]
However, when I try to extract the same memory variable as defined by m/scan , it behaves differently in the context of m/rewrites:
(m/rewrites [1 2 "a" "b" "c"]  (m/scan (m/pred string? !s)) 
                                    [:ul . [:li !s] ...])
=> ([:ul [:li "a"]] [:ul [:li "b"]] [:ul [:li "c"]])
I assume this is because m/rewrites always expects to return a sequential collection and thus ignores the head/tail delimiting with . and ... that works in the context of m/subst. m/rewrite doesn't work here because it only returns the first value of the memory variable. I'm not quite sure how to proceed - what method should I be using instead? Any guidance is much appreciated!

noprompt 2020-06-16T18:12:40.419500Z

@afoltzm is this the result you are looking for?

(m/rewrites [1 2 "a" "b" "c"]
  (m/seqable (m/or (m/pred string? !s) _) ...) 
  [:ul . [:li !s] ...])
;; =>
([:ul [:li "a"] [:li "b"] [:li "c"]]
 [:ul [:li "a"] [:li "b"]]
 [:ul [:li "a"] [:li "c"]]
 [:ul [:li "a"]]
 [:ul [:li "b"] [:li "c"]]
 [:ul [:li "b"]]
 [:ul [:li "c"]]
 [:ul])

noprompt 2020-06-16T18:13:56.420800Z

In situations where you want to find all the possible ways to project some values into a memory variable you’ll want to use the (m/or pattern-with-mem-vars _) technique. Memory variables, unlike logic variables, are always initialized which is why you can use them like this.

noprompt 2020-06-16T18:14:57.421400Z

Note, you can replace m/seqable with [,,,] etc.

respatialized 2020-06-16T18:20:44.423Z

@noprompt I'm only interested in the first result. is there a simpler way to express the case with the maximal set of results, or should I just take the first value? thanks for the quick response!

noprompt 2020-06-16T18:21:32.423700Z

Using rewrite in the above example will yield

[:ul [:li "a"] [:li "b"] [:li "c"]]

1
noprompt 2020-06-16T18:23:51.425200Z

We try and respond as quickly as we can here. 🙂

respatialized 2020-06-16T18:25:56.426800Z

I knew there had to be a way with m/rewrite even if I wasn't sure what it was. It's taken me a fair bit to wrap my head around term rewriting, but the old Alan Perlis quotation comes to mind as I work through the examples - "A language that doesn't affect the way you think about programming, is not worth knowing." Thanks again.

noprompt 2020-06-16T18:32:06.429500Z

It definitely has that effect. Maude, TXL, and StrategoXT, to name a few, influenced me and fundamentally changed my thoughts on what program is and could be.

noprompt 2020-06-16T18:33:06.430600Z

Having Meander in Clojure has been personally interesting to me because it wasn’t until I was able to get it off the ground that I could start messing with the ideas in a different setting: the REPL.

noprompt 2020-06-16T18:34:43.431500Z

BTW, for anyone interested, have a look at those languages if you have the spare time to do so. Maude, in particular, was really interesting to me.

noprompt 2020-06-16T18:35:32.432400Z

I’m hoping that within the next year or so we can get zeta off the ground and have some of the power of model checking in Clojure.

respatialized 2020-06-16T19:18:22.437700Z

One more question. I want to do the following: 1. For every item in a sequence: 2a. If that item matches a predicate with m/pred, split that item into a subsequence with m/app, collect the items in that subsequence into a memory variable !is , and then insert those values into the enclosing sequence in order. (e.g. something like (m/app #(clojure.string/split % #"|") "a|b|c") ) 2b. If that item doesn't match a predicate, leave it as-is in the same position.

jimmy 2020-06-16T19:22:42.438600Z

(m/rewrite ["ad,sf" 1 "asd,fa,sdf" 2 3]
  [(m/or 
    (m/and (m/pred string?) (m/app #(clojure.string/split % #",") [!xs ...]))
    !xs) ...]
  [!xs ...])

;; =>

["ad" "sf" 1 "asd" "fa" "sdf" 2 3]
@afoltzm Is this what you mean?

1💯
respatialized 2020-06-16T19:23:22.438900Z

@jimmy precisely!

respatialized 2020-06-16T19:26:00.440300Z

I guess I still don't fully understand how the combinators in meander work because I didn't realize you could use m/and to combine a predicate with a function application. Thanks for clarifying!

noprompt 2020-06-16T19:29:33.441900Z

You can also do (m/pred string? (m/app ,,,)))

1➕
jimmy 2020-06-16T19:31:12.443900Z

All I did was do the little ‘and’ and ‘or’ trick to emulate an if statement. Used to have to do it all the time in complex (and terrible) sql stored procedures. and and or in meander work just like their logical counterparts.

(map (fn [x]
       (or
        (and (string? x) (clojure.string/split x #","))
        x))
     ["ad,sf" 1 "asd,fa,sdf" 2 3])