Fork me on GitHub
#meander
<
2020-03-31
>
yuhan02:03:19

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]} ...])
;; => []

timothypratley20:03:54

@qythium @U06MDAPTP 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. /shrug

yuhan02:03:18

Based on the first result I would expect the second to produce [{:k []}]

noprompt03:03:50

@qythium I think so. This probably has something to do with how compiles.

noprompt03:03:08

There’s a runtime check to see if the memory variables have been exhausted.

yuhan03:03:43

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 😕

noprompt03:03:56

I’m sorry about that and I agree with you.

noprompt03:03:55

FWIW I’m working to make these problems go away.

👍 4
noprompt03:03:47

But in this case its not the ..!n that is the problem its actually the in this case.

yuhan03:03:06

no discouragement intended!

noprompt03:03:07

Memory variables do not have this problem on zeta.

noprompt03:03:26

Nor does .

noprompt03:03:02

I think the mistake I made in epsilon down is trying to bind everything in Clojure.

noprompt03:03:38

The code comes out fast but its also been harder to debug.

noprompt03:03:16

In zeta I decided to manage the bindings at runtime with a map.

noprompt03:03:16

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.

yuhan03:03:39

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?

noprompt03:03:14

I think thats a valid concern and thats why I patch epsilon.

noprompt03:03:23

There’s little use of ..!n at the moment.

noprompt03:03:19

90% of the parser/compiler stuff is built with logic variables. I do use a handful of memory variables but there’s no nesting.

noprompt03:03:04

I’ll think about the best way to fix that bug in epsilon.

noprompt03:03:18

If you have an idea for a patch that’d be good.

noprompt03:03:31

I’m not sure if swapping out an or would be safe or not.

yuhan03:03:44

Thanks! I probably can't help here, don't know much about the internals

noprompt03:03:17

Thats fine. But I hope it gives you confidence know that I’m not trying to cut corners.

noprompt03:03:10

The logic makes sense as: If epsilon has a bug And zeta uses epsilon to build zeta Then epsilon should be patched 🙂

noprompt03:03:56

And, also, I kind of depend on bug reports.

yuhan03:03:45

will provide as many as I can 🙂

yuhan03:03:52

unrelated question, what's the best way of providing "default" values for variables?

(m/rewrite {}
  {:k ?v}
  {:k ~(or ?v :default)})

yuhan03:03:24

this works for logic vars but gives an error on

(m/rewrite [{}]
  [{:k !v} ...]
  [{:k ~(or !v :default)} ...])

noprompt03:03:49

There’s always

(m/or pattern-containing-?x (m/let [?x :default]))

noprompt03:03:00

Or

{:k (m/or (m/and nil (m/let [?x :default]))
          ?x}

yuhan03:03:53

That doesn't seem to work for mem vars as well?

yuhan03:03:12

(m/rewrite [{}]
  [{:k (m/or !v (m/let [!v :default]))} ...]
  [{:k !v} ...])
;; => [{:k nil}]

noprompt03:03:27

(me/rewrite [{}]
  [{:k (me/or (me/let [!v :default]) !v)} ...]
  [{:k !v} ...])
;; =>
[{:k :default}]

noprompt03:03:25

!v is [nil] in your example cause !v is matched against (get m :k)

yuhan03:03:32

but that binds all !v to :default

yuhan03:03:48

(m/rewrite [{:k :exists} {}]
  [{:k (m/or (m/let [!v :default]) !v)} ...]
  [{:k !v} ...])
;; => [{:k :default} {:k :default}]

noprompt03:03:12

You want something like the example I gave

(m/or (m/and nil (m/let [!v :default]))
      !v)

noprompt03:03:45

(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"}]

noprompt03:03:28

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.

noprompt03:03:24

(default nil ?x :default)
If the value matches nil pattern match ?x against :default otherwise pattern match with ?x.

yuhan04:03:03

nice, thanks!

noprompt04:03:43

Just noticed I wrote (or (or ,,,) ,,,) when I meant (or (and ,,,) ,,,)

noprompt04:03:47

@qythium by switching that and to an or in the substitution compiler I get

(rewrite [{}]
  [{:k (seqable !x ..!n)} ...]
  [{:k [!x ..!n]} ...])
;; =>
[{:k []}]

noprompt04:03:11

And

(rewrite {}
  {:k (seqable !x ..!n)}
  {:k [!x ..!n]})
;; =>
{:k []}

noprompt04:03:29

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] ...])))

noprompt04:03:46

Maybe the check should only be looking at memory variables that are top-level to the

noprompt04:03:23

Eh, but actually, I don’t think thats right either.

noprompt19:03:08

Would m/recur be a better name than m/cata?

20