Is this a bug?
(m/rewrite {}
{:k (m/seqable !x ..!n)}
{:k [!x ..!n]})
;; => {:k []}
(m/rewrite [{}]
[{:k (m/seqable !x ..!n)} ...]
[{:k [!x ..!n]} ...])
;; => []
@qythium @noprompt FWIW just wanted to add my 2c that I’ve encountered this and found that using named collectors is usually the ticket in my usage:
(m/rewrite [{}]
[{:k (m/seqable !x ..!n)} ...]
[{:k [!x ..!n]} ...])
=> []
(m/rewrite [{}]
[{:k (m/seqable !x ..!n)} ..!m]
[{:k [!x ..!n]} ..!m])
=> [{:k []}]
To me this seemed logical because I think of …
as disperse everything without context. /shrugBased on the first result I would expect the second to produce [{:k []}]
@qythium I think so. This probably has something to do with how …
compiles.
This is the line: https://github.com/noprompt/meander/blob/epsilon/src/meander/substitute/epsilon.cljc#L334
There’s a runtime check to see if the memory variables have been exhausted.
I think I'll just avoid the ..!n
construct entirely for now... it seemed so useful at first but it's just been a source of bugs and headaches 😕
I’m sorry about that and I agree with you.
FWIW I’m working to make these problems go away.
But in this case its not the ..!n
that is the problem its actually the …
in this case.
no discouragement intended!
Memory variables do not have this problem on zeta
.
Nor does …
.
I think the mistake I made in epsilon
down is trying to bind everything in Clojure.
The code comes out fast but its also been harder to debug.
In zeta
I decided to manage the bindings at runtime with a map.
Its slightly slower to execute a zeta
pattern match but its also much easier to manage and iteratively improve than starting at the lowest level first.
What slightly worries me about Zeta's bootstrapping is that if there are still correctness issues with the epsilon logic that's used to compile it, will that mean that it's all going to be a black box built on a uncertain foundation?
I think thats a valid concern and thats why I patch epsilon
.
There’s little use of ..!n
at the moment.
90% of the parser/compiler stuff is built with logic variables. I do use a handful of memory variables but there’s no nesting.
I’ll think about the best way to fix that bug in epsilon
.
If you have an idea for a patch that’d be good.
I’m not sure if swapping out an or
would be safe or not.
Thanks! I probably can't help here, don't know much about the internals
Thats fine. But I hope it gives you confidence know that I’m not trying to cut corners.
The logic makes sense as:
If epsilon
has a bug
And zeta
uses epsilon
to build zeta
Then epsilon
should be patched
🙂
QED
😛
And, also, I kind of depend on bug reports.
will provide as many as I can 🙂
unrelated question, what's the best way of providing "default" values for variables?
(m/rewrite {}
{:k ?v}
{:k ~(or ?v :default)})
this works for logic vars but gives an error on
(m/rewrite [{}]
[{:k !v} ...]
[{:k ~(or !v :default)} ...])
There’s always
(m/or pattern-containing-?x (m/let [?x :default]))
Or
{:k (m/or (m/and nil (m/let [?x :default]))
?x}
That doesn't seem to work for mem vars as well?
(m/rewrite [{}]
[{:k (m/or !v (m/let [!v :default]))} ...]
[{:k !v} ...])
;; => [{:k nil}]
(me/rewrite [{}]
[{:k (me/or (me/let [!v :default]) !v)} ...]
[{:k !v} ...])
;; =>
[{:k :default}]
!v
is [nil]
in your example cause !v
is matched against (get m :k)
but that binds all !v
to :default
(m/rewrite [{:k :exists} {}]
[{:k (m/or (m/let [!v :default]) !v)} ...]
[{:k !v} ...])
;; => [{:k :default} {:k :default}]
You want something like the example I gave
(m/or (m/and nil (m/let [!v :default]))
!v)
(me/rewrite [{} {:k "i have a value"}]
[{:k (me/or (me/and nil (me/let [!v :default])) !v)} ...]
[{:k !v} ...])
;; =>
[{:k :default} {:k "i have a value"}]
You could do
(me/defsyntax default [match p clojure-expr]
`(me/or (me/and ~match (me/let [~p ~clojure-expr])) ~p))
with maybe better name.(default nil ?x :default)
If the value matches nil
pattern match ?x
against :default
otherwise pattern match with ?x
.nice, thanks!
Just noticed I wrote (or (or ,,,) ,,,)
when I meant (or (and ,,,) ,,,)
@qythium by switching that and
to an or
in the substitution compiler I get
(rewrite [{}]
[{:k (seqable !x ..!n)} ...]
[{:k [!x ..!n]} ...])
;; =>
[{:k []}]
And
(rewrite {}
{:k (seqable !x ..!n)}
{:k [!x ..!n]})
;; =>
{:k []}
There are two failures though
FAIL in meander.epsilon-test/subst-mvr-rp*-test (epsilon_test.cljc:2023)
expected: [[1 :a] [2 :b]]
actual: [[1 :a] [2 :b] [3 nil]]
diff: + [nil nil [3 nil]]
FAIL in meander.epsilon-test/subst-mvr-rp*-test (epsilon_test.cljc:2025)
expected: [[:a 1] [:b 2]]
actual: [[:a 1] [:b 2] [nil 3]]
diff: + [nil nil [nil 3]]
from these tests
(let [!1s [1 2 3]
!2s [:a :b]]
,,,
(t/is (= [[1 :a] [2 :b]]
(r/subst [[!1s !2s] ...])))
(t/is (= [[:a 1] [:b 2]]
(r/subst [[!2s !1s] ...])))
Maybe the check should only be looking at memory variables that are top-level to the …
Eh, but actually, I don’t think thats right either.
Would m/recur
be a better name than m/cata
?
I vote yes
+1