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.
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).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???
..?n-?m
seems to make sense :thinking_face:
And it can express:
..0-1
and ..1-?n
to follow regex ?
and +
rulesā¦
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 š
@noprompt any thoughts?
@jimmy ^^
I was planning to add a more verbose operator to zeta
(m/repeated patterns ,,, :min <min-pattern> :max <max-pattern>)
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 starIgnoring 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
@jimmy You mean adding m/repeated
?
Maybe? At the very least some more flexible repeat operator, or covering some we don't have.
Oh sweet, I think you are saying: (if (integer? n) ā¦) could be: if + return min-length 1 if ? return max-length 1
that seems easy and powerful š
for :rp+
Ahhh dumb question from meā¦ what are :rp* and :rp+ ? š
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)
Thatās 3 or more. But we really need a thing allows more control.
Oh well just to enumerate some optionsā¦
..2..5
might be swell š
..2-5
is great but I worry that kebab variables might not make sense
..?a-?b
for example seems ok, but
..?some-weird-name-?some-other-name
seems ambiguous
where ..?some-weird-name..?some-other-name
is more obvious
In hindsight I wish ..3
meant exactly 3, and ..3..
meant 3 or more š
FWIW Iām pretty sure just ..?
is need, because ..1
is exactly ..+
anyhow
..0..1
is more precise though
Yeah and that syntax is actually allowed by the reader.
Wouldnāt ..3..3
be exactly three?
yup
:thumbsup:
The thing I donāt have an answer for is in this regard is the greediness.
Because ..?n..?m
can have many solutions depending on the situation.
Same goes for ..?n..?n
Hmmm isnāt it just a mechanical translation to the min/max multimethods though?
Iām not sure I follow
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?oh if they are both unbound its a different case
got it
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.Well you know my preference is greedy everything š
Yah, and I suspect thats the case for many, but not all patterns.
But in the short term we could also just punt and say donāt support variables in both places
But this is way more important for subsitution.
I think just supporting number (without variables) would already be a big step forward
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.So greed becomes relevant.
Its not really a point of contention in traditional matches because ambiguity is excluded by design.
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.
> I think just supporting number (without variables) would already be a big step forward
Do you just mean something like ..3..10
?
yes š
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.
Sorry for dropping the ball on this conversation, Iāve been on vacation. Iām open to updating the epsilon syntax to support this.
Yeah I personally am in favor of having an optional operator. But there are some complications because of meanders more advanced functionality.
The zeta
version of the project will support the regex style ?
operator with the caveat that logic variables must be handled.
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)]
but can only appear at the end š
wellā¦ I guess you can nest expressions
if you make ?tail be something more complicated.
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.
On the zeta
branch, its possible to stack &
such that you can write
(?x & (? 2 ?tail) & ?other-tail)
(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.
looks like optional things canāt be variables with this techniqueā¦ a let would be required to make it nil
ie: to solve the original problem of maybe docstrings maybe meta
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.
bah I guess Iām putting the or in the wrong spot
(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]
^^ but this canāt neatly be wrapped in a defsyntax
The thing I like about using a memory variable is that the semantics for substitution remain clear š
So I feel itās a more symmetric approach.
n = 0|1 is just a subset of many constraints
like I want 1 or more (hint hint, regex +)
in reality I only care about 0 or 1, and 1 or more though.