meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
pbaille 2020-05-05T06:22:05.198800Z

thank you for the exemple, it is nice, the with form is really powerful , I can honestly say that meander is the most exciting clojure lib i've seen for a long time! I hope it will continue to grow šŸ™‚ thank you a lot for the hard work.

pbaille 2020-05-05T06:32:43.205800Z

Here how the https://github.com/cgrand/seqexp lib handle a similar thing (simplified). this is sweet I think:

;; match a defn-like body (including name, optional docstring, optional metadata
;; and multiple arities)
=> (def args+body (se/cat vector? (se/* se/_)))

#'playground/args+body

=> (se/exec
     (se/cat
       (se/as :name symbol?)
       (se/? (se/as :docstring string?))
       (se/? (se/as :meta map?))
       (se/|
         (se/as :body args+body)
         (se/as :bodies
           (se/+ (partial se/exec args+body)))))
     '(fn-name "some-doc" {:meta :data}
        ([a] ...)
        ([a b] ...)))

{:rest (), :match (fn-name "some-doc" {:meta :data} ([a] ...) ([a b] ...)),
 :bodies (([a] ...) ([a b] ...)),
 :name (fn-name),
 :docstring ("some-doc"),
 :meta ({:meta :data})}
does the se/? (zero or one) can be abstracted via defsyntax? I've seen that in the implementation there is a possibility to set the maximal occurence count of a repeated pattern, could we use that to do so ? do you think that something like ..0-1 for expressing such thing makes sense ? (I didn't had time to hack it but I will certainly try someday).

timothypratley 2020-05-05T21:02:22.213100Z

I for one love the idea of something like ..0-1 can we brainstorm on it a bit? I think 0-1 is maybe a bit too range oriented, but maybe thatā€™s perfect???

timothypratley 2020-05-05T21:02:38.213300Z

..?n-?m seems to make sense :thinking_face:

timothypratley 2020-05-05T21:06:40.214100Z

And it can express: ..0-1 and ..1-?n to follow regex ? and + rulesā€¦

timothypratley 2020-05-05T21:08:35.214300Z

Alternatively going straight to ..? and ..+ might be more direct, but less flexible (as you canā€™t say I want 3-5ā€¦ or support both!!! everything šŸ™‚

timothypratley 2020-05-05T21:09:26.214500Z

@noprompt any thoughts?

timothypratley 2020-05-05T21:09:35.214700Z

@jimmy ^^

noprompt 2020-05-05T21:10:55.214900Z

I was planning to add a more verbose operator to zeta

(m/repeated patterns ,,, :min <min-pattern> :max <max-pattern>)

noprompt 2020-05-05T21:13:29.215100Z

If you did something like

(m/repeated 1 :min ?n :max ?n)
you get a greedy star
(m/repeated 1 :min 0 :max ?n)
youā€™d get an increasingly greed star

jimmy 2020-05-05T21:16:27.215300Z

Ignoring syntax for a second. I think this should be achievable in epsilon. You can see the various repeat length things defined here. Should be able to add a new type. https://github.com/noprompt/meander/blob/afc410d6d82f719cf8f39c4fedf5b1cdb761fb21/src/meander/syntax/epsilon.cljc#L1172-L1276

noprompt 2020-05-05T21:17:32.215600Z

@jimmy You mean adding m/repeated?

jimmy 2020-05-05T21:18:52.215800Z

Maybe? At the very least some more flexible repeat operator, or covering some we don't have.

timothypratley 2020-05-05T21:21:09.216Z

Oh sweet, I think you are saying: (if (integer? n) ā€¦) could be: if + return min-length 1 if ? return max-length 1

timothypratley 2020-05-05T21:21:32.216200Z

that seems easy and powerful šŸ™‚

timothypratley 2020-05-05T21:21:52.216400Z

for :rp+

timothypratley 2020-05-05T21:30:04.216800Z

Ahhh dumb question from meā€¦ what are :rp* and :rp+ ? šŸ™‚

timothypratley 2020-05-05T21:37:19.217Z

it looks like :rp* is ā€¦ and :rp+ is ..3 but I got confused because :rp+ returns max length Inf (which maybe doesnā€™t matter, I just thought it would be 3)

noprompt 2020-05-05T21:56:46.218200Z

Thatā€™s 3 or more. But we really need a thing allows more control.

timothypratley 2020-05-05T22:00:01.219500Z

Oh well just to enumerate some optionsā€¦ ..2..5 might be swell šŸ™‚

timothypratley 2020-05-05T22:00:31.219700Z

..2-5 is great but I worry that kebab variables might not make sense

timothypratley 2020-05-05T22:01:20.219900Z

..?a-?b for example seems ok, but ..?some-weird-name-?some-other-name seems ambiguous

timothypratley 2020-05-05T22:01:58.220100Z

where ..?some-weird-name..?some-other-name is more obvious

timothypratley 2020-05-05T22:03:14.220300Z

In hindsight I wish ..3 meant exactly 3, and ..3.. meant 3 or more šŸ˜›

timothypratley 2020-05-05T22:05:13.220500Z

FWIW Iā€™m pretty sure just ..? is need, because ..1 is exactly ..+ anyhow

timothypratley 2020-05-05T22:06:16.220700Z

..0..1 is more precise though

noprompt 2020-05-05T22:06:31.220900Z

Yeah and that syntax is actually allowed by the reader.

noprompt 2020-05-05T22:08:17.221100Z

Wouldnā€™t ..3..3 be exactly three?

timothypratley 2020-05-05T22:08:23.221300Z

yup

timothypratley 2020-05-05T22:08:34.221500Z

:thumbsup:

noprompt 2020-05-05T22:09:42.221700Z

The thing I donā€™t have an answer for is in this regard is the greediness.

noprompt 2020-05-05T22:10:22.221900Z

Because ..?n..?m can have many solutions depending on the situation.

noprompt 2020-05-05T22:10:55.222100Z

Same goes for ..?n..?n

timothypratley 2020-05-05T22:10:59.222300Z

Hmmm isnā€™t it just a mechanical translation to the min/max multimethods though?

timothypratley 2020-05-05T22:11:05.222500Z

Iā€™m not sure I follow

timothypratley 2020-05-05T22:12:16.222700Z

Like here:

;; 3
       (nat-int? count-pattern)
       (clj/let [?n count-pattern
                 ellipsis (clj/symbol (str ".." ?n))]
         `(and (seqable (or (and ~pattern !gather#) _gather#) ~ellipsis)
               (guard (<= ~?n (count !gather#)))))
Just needs to consider guarding the max as well?

timothypratley 2020-05-05T22:13:04.222900Z

oh if they are both unbound its a different case

timothypratley 2020-05-05T22:13:07.223100Z

got it

noprompt 2020-05-05T22:13:10.223300Z

Even with min/max constraints you still need a way to specify greediness. The example would be something like

[!xs * !ys ...]
Where the * represents the greedy Kleene star. In this case !ys should never collect any values because of the greediness.

timothypratley 2020-05-05T22:13:39.223500Z

Well you know my preference is greedy everything šŸ™‚

noprompt 2020-05-05T22:13:56.223700Z

Yah, and I suspect thats the case for many, but not all patterns.

timothypratley 2020-05-05T22:14:00.223900Z

But in the short term we could also just punt and say donā€™t support variables in both places

noprompt 2020-05-05T22:14:09.224100Z

But this is way more important for subsitution.

timothypratley 2020-05-05T22:14:24.224300Z

I think just supporting number (without variables) would already be a big step forward

noprompt 2020-05-05T22:16:02.224500Z

On zeta the pattern

[!xs ... !ys ...]
on the RHS produces all possible ways to drain the !xs and !ys and though this is interesting and right in the eyes of searching/generation being categorical duals, its probably not what you want 99% of the time.

noprompt 2020-05-05T22:16:25.224700Z

So greed becomes relevant.

noprompt 2020-05-05T22:16:46.224900Z

Its not really a point of contention in traditional matches because ambiguity is excluded by design.

noprompt 2020-05-05T22:17:52.225100Z

Meander is working from a different direction, especially on zeta, where the starting point is ambiguity; being able produce a full space of solutions by all possible ways to yield bindings on the LHS and generate data using those bindings on the RHS.

noprompt 2020-05-05T22:18:36.225300Z

> I think just supporting number (without variables) would already be a big step forward

noprompt 2020-05-05T22:18:48.225500Z

Do you just mean something like ..3..10 ?

timothypratley 2020-05-05T22:23:33.225900Z

yes šŸ™‚

timothypratley 2020-05-05T22:25:46.226100Z

The basic form solves 2 real and recurring case in my mind: 0 or 1 optional semantics, and exactly 50 matches. And also covers everything in between.

noprompt 2020-05-18T22:53:37.243600Z

Sorry for dropping the ball on this conversation, Iā€™ve been on vacation. Iā€™m open to updating the epsilon syntax to support this.

jimmy 2020-05-05T15:40:04.207100Z

Yeah I personally am in favor of having an optional operator. But there are some complications because of meanders more advanced functionality.

noprompt 2020-05-05T17:46:17.209800Z

The zeta version of the project will support the regex style ? operator with the caveat that logic variables must be handled.

noprompt 2020-05-05T17:46:29.210200Z

You can do something like this, however,

(m/defsyntax ? [pattern tail]
  `(m/with [%tail# ~tail]
     (m/seqable & (m/or (m/seqable ~pattern & %tail#)
                        %tail#))))

(m/match '(1 3 4)
  (?x & (? 2 ?tail))
  [?x ?tail])
;; => [1 (3 4)]

(m/match '(1 2 3 4)
  (?x & (? 2 ?tail))
  [?x ?tail])
;; => [1 (3 4)]

timothypratley 2020-05-05T20:19:13.210300Z

but can only appear at the end šŸ˜ž

timothypratley 2020-05-05T20:19:46.210500Z

wellā€¦ I guess you can nest expressions

timothypratley 2020-05-05T20:20:15.210700Z

if you make ?tail be something more complicated.

noprompt 2020-05-05T20:36:22.210900Z

Iā€™ve been considering a way to make extensible infix operators like ? or & or whatever but I feel a lot of uncertainty about the implications.

noprompt 2020-05-05T20:37:45.211100Z

On the zeta branch, its possible to stack & such that you can write

(?x & (? 2 ?tail) & ?other-tail)

timothypratley 2020-05-05T20:41:54.211300Z

(m/match [1 ā€œthis is fineā€ :foo] (?n & (? ?s ((m/pred keyword? ?k)))) [?x ?s ?k]) Syntax error macroexpanding meander.match.epsilon/match at (scratch.clj:10:1). Every pattern of an or pattern must have references to the same unbound logic variables.

timothypratley 2020-05-05T20:43:02.211500Z

looks like optional things canā€™t be variables with this techniqueā€¦ a let would be required to make it nil

timothypratley 2020-05-05T20:43:26.211700Z

ie: to solve the original problem of maybe docstrings maybe meta

timothypratley 2020-05-05T20:44:56.211900Z

but this doesnā€™t work either: (m/match [1 ā€œthis is fineā€ :foo] (?n & (? (m/or ?s (m/let [?s nil])) ((m/pred keyword? ?k)))) [?x ?s ?k]) Syntax error macroexpanding meander.match.epsilon/match at (scratch.clj:10:1). Every pattern of an or pattern must have references to the same unbound logic variables.

timothypratley 2020-05-05T20:45:13.212100Z

bah I guess Iā€™m putting the or in the wrong spot

timothypratley 2020-05-05T20:53:56.212300Z

(m/match [1 "this is fine" :foo]
  [(m/pred number? ?n) & (m/with [%tail [(m/pred keyword? ?k)]]
                           (m/or [(m/pred string? ?s) & %tail]
                                 (m/and (m/let [?s nil])
                                        %tail)))]
  [?n ?s ?k])
;; => [1 nil :foo]

timothypratley 2020-05-05T20:54:08.212500Z

^^ but this canā€™t neatly be wrapped in a defsyntax

timothypratley 2020-05-05T20:59:30.212700Z

The thing I like about using a memory variable is that the semantics for substitution remain clear šŸ˜›

timothypratley 2020-05-05T20:59:39.212900Z

So I feel itā€™s a more symmetric approach.

timothypratley 2020-05-05T21:03:47.213500Z

n = 0|1 is just a subset of many constraints

timothypratley 2020-05-05T21:04:00.213700Z

like I want 1 or more (hint hint, regex +)

timothypratley 2020-05-05T21:04:44.213900Z

in reality I only care about 0 or 1, and 1 or more though.