is there a nicer way to have an optional subpattern, like:
(m/or {:foo ?bar :baz ?baf} (m/let [?bar nil ?baf nil]))
like m/?
in glob lingo kind of
Not really but I’m working toward having a thing like this on next branch of the project.
cool thanks!
Most of the time, this is fine. Actually, I think it’s nice that there’s no convenience for this because it has a tendency to encourage models that have more consistency. That’s just me though. OTOH I think defaults for unbound logic variables is useful and has a place.
more consistency?
For maps though, we don’t check if the key has a value. We use get not find.
yep
seems like a lot of times the structure you're maching against may be optimized for size
so there will be optional parts
By consistency I mean, a data model that doesn’t have a bunch of optionality. Some optionality is fine and it’s why map patterns work they way the do. But optionality implies logic putting more branches in the code if it’s not defaulted before moving it downstream.
But I want the pattern matcher to be strict by default with the option to be less restrictive if you need.
And I’m working toward that second part! 😄
i was looking in &env
for bindings
I can put those in there.
to use defsyntax to implement this
But what you want is to use the parser to get the variables of the pattern passed in so that you can make the let
hah or you can cheat and just look for them with tree seq or something! 😉
(That’s more dangerous though.)
haha yes, that would be the easy way for sure
i see some examples, like subst
parses the form
All of this stuff will get better though in time.
I can help more in a bit but it sounds like you’ll figure it out. 👍
yeah so far pretty smooth!
Fair warning: there’s a ton of code in there and mostly its because I was on new ground and exploring new techniques and ideas. The code on the zeta
arm is being written mostly with epsilon
and compiled to Clojure that uses the new zeta
runtime. The quality of the implementation is much, much better.
sounds great
(defsyntax opt
[pattern]
(let [syms (atom [])]
(->> (r.subst.syntax/parse pattern &env)
(walk/prewalk #(let [t (:tag %) s (:symbol %)]
(when (and (map? %) (#{:lvr :mvr} t))
(swap! syms into [s (when (= t :mvr) [])]))
%)))
`(e/or ~pattern (e/let [~@(deref syms)]))))
@micha There are some utilities for pulling out variables like this.
(require '[meander.match.syntax.epsilon :as m.match.syntax])
(require '[meander.syntax.epsilon :as m.syntax])
(defsyntax opt
[pattern]
(let [syms (atom [])]
(if (m/match-syntax? &env)
(let [ast (m.match.syntax/parse pattern &env)
lvars (m.syntax/logic-variables ast)
binding-patterns (mapcat (juxt :symbol (constantly nil)) lvars)]
`(m/or pattern (m/let [~@binding-pattersn])))
&form)))
You really only need to ask for logic variables because memory variables are always bound to []
even if they don’t match anything. This is why something like
[(or (pred odd? !odds) (pred even? !evens) ...]
works with no complaints from the compiler. Logic variables can’t be initialized like this.oh sweet