meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
jimmy 2019-12-12T01:19:33.475100Z

https://github.com/noprompt/meander/pull/92

2019-12-12T02:45:18.476200Z

re

(let [data (map hash-map
            (repeat :regression-test-success?)
            (cycle [true false]))
      regression-suite (take 10 data)]
  (m/find regression-suite
    (m/gather {:regression-test-success? true
               :as !success-test-records}
              ?count)
    [!success-test-records ?count]))
How can I extend this example to m/search ? I'd love to compute the total successes and failures in the same meander program.

jimmy 2019-12-12T18:34:29.480600Z

If all you want is the number of success and failures you don't need to use search. You can do this.

(let [data (map hash-map
                (repeat :regression-test-success?)
                (cycle [true false]))
      regression-suite (take 10 data)]
  (m/match regression-suite
    (m/seqable (m/or {:regression-test-success? true
                      :as !success-test-records}
                     {:regression-test-success? false
                      :as !fail-test-records}) ...)
    {:fails (count !fail-test-records)
     :successes (count !success-test-records)}))

2019-12-12T21:26:13.486400Z

Thanks. I'm having trouble understanding the difference between m/sequable and m/scan

jimmy 2019-12-13T00:11:50.488700Z

(seqable &lt;pattern&gt; ...) is like [<pattern> …] but works for anything in clojure that is seqable. That means that everything in the collection must match that pattern. (scan &lt;pattern&gt;) actually expands to something like [_ ... &lt;pattern&gt; . _ ...]. Scan is looking for anywhere in the collection that the pattern could exist. Scan actually allows you to try and match on multiple patterns. It will search through the collection finding all the elements that can match your pattern and ignore all the rest. Scan must be used with search Finally (gather &lt;pattern&gt;) says find me all the things in the collection that match this pattern and gather them up for me. Anything that doesn’t match I don’t care about it. I should think about writing an article explaining these. None of them are actually primitive. They are things we have found useful and added to meander, but they are all just extensions built on top of the base.

1👍
2019-12-13T00:29:52.489Z

This is helpful. Thanks. I noticed an Github issue to write a top-down tutorial. I think that would help me a lot. It's been a long time since term rewriting systems in school and I'm finding it hard to see the forest for the trees.

eraserhd 2019-12-12T17:37:26.478500Z

Hmm, I frequently want a non-backtracking or in m/search. e.g. (m/x-or (m/pred number? ?x) (let [?x 0])) instead of (m/or (m/pred number? ?x) (m/pred (complement number?) (m/let [?x 0]))).

eraserhd 2019-12-12T17:37:53.479Z

I shall try defsyntax. But what would this be called? Is there a precedent for the name?

eraserhd 2019-12-12T17:40:36.479500Z

Or maybe a cut operator?

eraserhd 2019-12-12T17:56:13.480400Z

(m/match [42 76] [?a . (m/app #(+ ?a %) !b) ...] [?a !b]) ;=&gt; [42 [118]], but (m/match [42 76] [?a . (m/or (m/app #(+ ?a %) !b) _) ...] [?a !b]) ;=&gt; Unable to resolve symbol ?a.

noprompt 2019-12-13T19:57:56.000300Z

@eraserhd I’m thinking about #3 a bit now. What do you think of this sketch?

(m/compute ?result + ?a ?b)
;; `?a` and `?b` must be bound
;; `?result` matches the result of the function application.

noprompt 2019-12-13T19:58:43.000500Z

This is venturing near constraint territory.

noprompt 2019-12-13T19:59:02.000700Z

(m/compute true &lt; ?a ?b)

eraserhd 2019-12-13T20:06:14.000900Z

hmm.

eraserhd 2019-12-13T20:07:45.001100Z

This is pretty close to m/let.

eraserhd 2019-12-13T20:08:51.001300Z

m/let presumably has the same problems as m/app wrt captured variables?

eraserhd 2019-12-13T20:16:01.001500Z

I think m/compute is slightly awkward.

eraserhd 2019-12-13T20:16:15.001700Z

I wouldn't bat an eye if that's what I got.

eraserhd 2019-12-13T20:18:25.001900Z

(m/compute ?result (+ ?a ?b)) feels slighty better. In this example, only a list with simple subexpressions is allowed.

eraserhd 2019-12-13T20:20:02.002100Z

There's a form like this in Datomic. It's not clearly defined what is allowed in subexpressions in Datomic, and occasionally I can get away with something useful, but not much.

eraserhd 2019-12-13T20:20:22.002300Z

In Datomic, [(+ ?a ?b) ?result].

eraserhd 2019-12-13T20:21:09.002500Z

IIRC, [(+ ?a (+ 1 2)) ?result] works, but [(+ ?a (+ 1 ?b)) ?result] does not.

eraserhd 2019-12-13T20:21:15.002700Z

(variables have to be at the top)

eraserhd 2019-12-13T20:23:22.002900Z

And, I guess this is just let with a rule that any variables are at the top.

noprompt 2019-12-13T20:42:54.003100Z

I think something like

(m/compute result-pattern fn-pattern arg-patterns ...)
might be have some useful properties because fn-pattern can be bound to a fn from Clojure explicitly
(m/compute ?res ~+ ?a ?b)

noprompt 2019-12-13T20:43:30.003300Z

Its not clear to me what extra round braces provide.

noprompt 2019-12-13T20:45:03.003600Z

To be clear, I’m thinking of what the primitive form of this would be.

eraserhd 2019-12-13T20:45:22.003800Z

ah

noprompt 2019-12-13T20:46:07.004Z

Because I think m/app would emerge from this easily.

noprompt 2019-12-13T20:46:10.004200Z

(m/app inc ?res)
;; ==
(m/compute ?res ~inc)

eraserhd 2019-12-13T20:46:59.004400Z

Must all args, aside from f, be logic or memory variables?

noprompt 2019-12-13T20:47:07.004600Z

But also, we could get constraints out of this too.

noprompt 2019-12-13T20:47:19.004800Z

No.

noprompt 2019-12-13T20:47:36.005Z

(m/compute 2 ~+ 1 1) ;; matches
(m/compute 3 ~+ 1 1) ;; fails

eraserhd 2019-12-13T20:48:04.005300Z

Ok, then I like this.

noprompt 2019-12-13T20:48:31.005500Z

And if you would like round braces, of course, you could syntax that on later.

eraserhd 2019-12-13T20:48:43.005700Z

right

eraserhd 2019-12-13T20:50:07.005900Z

1. wacky idea - it's possible to attach metadata to things such that + could be reversible - e.g. ?result bound, but an arg not. Although, I guess that's also not a primitive?

eraserhd 2019-12-13T20:50:15.006100Z

2. does "constraints" imply unification?

noprompt 2019-12-13T20:50:37.006300Z

Maayybe.

eraserhd 2019-12-13T20:51:15.006500Z

hrmm. I can't think of a use for it. But I shall pay more attention.

noprompt 2019-12-13T20:52:06.006700Z

There have been a few cases of people talking about patterns like

(m/and ,,, (m/guard (&lt; 1 ?y)))

noprompt 2019-12-13T20:56:19.006900Z

Regarding unification, I’ve been wanting to venture more into that territory because there’s a lot of power there and whole bunch of stuff falls out. Pattern matching is a special case of unification where one of the terms being unified is ground.

noprompt 2019-12-13T21:00:29.007100Z

Back to 1. no that isn’t wacky but it would probably mean that we’d need to talk about domains.

noprompt 2019-12-13T21:02:12.007300Z

Which, honestly, that’s going to have to happen anyway.

noprompt 2019-12-13T21:04:34.007500Z

Because substitution currently does not have a failure semantic and it only computes a single result. We have an open ticket for generating values, this is essentially the search version of subst . A primary reason it hasn’t be started is that in order to do so a notion of failure is required.

eraserhd 2019-12-13T21:05:12.007700Z

hmm

eraserhd 2019-12-13T21:05:33.007900Z

that's kind of neat

noprompt 2019-12-13T21:06:15.008100Z

I think so too. 🙂 Shapes are kind of trippy.

eraserhd 2019-12-13T21:06:16.008300Z

this reminds me of a completely different use case I have - testing. The problem here is that it needs much better error messages.

noprompt 2019-12-13T21:06:28.008500Z

Totally!

eraserhd 2019-12-13T21:07:30.008700Z

btw, I read syntax.clj and some of ir.clj. Which, historically, predicts I'll contribute in a few weeks.

eraserhd 2019-12-13T21:07:54.008900Z

cljc :D

noprompt 2019-12-13T21:08:08.009100Z

Its a bit of a mess in there. I’m sorry. I tried to keep it tidy while also trying to push out code for Clojurist Together.

noprompt 2019-12-13T21:08:32.009300Z

I’ve started some work on the zeta branch; the pace there will be much slower.

noprompt 2019-12-13T21:09:15.009500Z

But epsilon is going to be around for a while longer and it’d probably be a good idea to make an issue or two for some of the design problems therein.

jimmy 2019-12-12T18:34:29.480600Z

If all you want is the number of success and failures you don't need to use search. You can do this.

(let [data (map hash-map
                (repeat :regression-test-success?)
                (cycle [true false]))
      regression-suite (take 10 data)]
  (m/match regression-suite
    (m/seqable (m/or {:regression-test-success? true
                      :as !success-test-records}
                     {:regression-test-success? false
                      :as !fail-test-records}) ...)
    {:fails (count !fail-test-records)
     :successes (count !success-test-records)}))

jimmy 2019-12-12T18:48:13.480900Z

app keeps the functions as opaque so when we generate things for or it doesn't know there is a variable in there.

{:cols
   [{:tag :wth,
     :bindings [],
     :body
     {:tag :vec,
      :prt
      {:tag :prt,
       :left {:tag :cat, :elements [{:tag :lvr, :symbol ?a}]},
       :right
       {:tag :prt,
        :left
        {:tag :rp*,
         :cat
         {:tag :cat,
          :elements
          [{:tag :meander.match.syntax.epsilon/apply,
            :function #(+ ?a %),
            :argument {:tag :mvr, :symbol !b},
            :meander.syntax.epsilon/original-form
            (m/app (+ ?a %) !b)}]}},
        :right {:tag :cat, :elements []}}},
      :as nil}}],
   :rhs {:value [?a !b], :op :return},
   :env #{},
   :refs {},
   :ref-specs {}}
Definitely a bug, but not sure what the right resolution would be. Maybe we can parse the function? Maybe we should reject those things? Honestly don't know.

jimmy 2019-12-12T18:50:15.481100Z

I'm guessing you need those search semantics for other things? If not, I find match to work fairly well for things like that.

noprompt 2019-12-12T18:58:13.484Z

You can’t rely on the logic variable being bound at that point and that’s due to how the pattern matching compiler operates. It prioritizes parts of the match over others; it’s part of the algorithm, not a bug.

jimmy 2019-12-12T18:58:59.484300Z

I mean it's a bug that we don't catch it and instead generate bad code.

noprompt 2019-12-12T19:01:43.485600Z

Since we don’t do analysis of the code we should probably call this out in the documentation somewhere.

noprompt 2019-12-12T19:06:03.486300Z

I wondered if cut would come up some day. 😄

2019-12-12T21:26:13.486400Z

Thanks. I'm having trouble understanding the difference between m/sequable and m/scan

noprompt 2019-12-12T21:50:38.488400Z

There’s this now if you want an short overview of how to make extensions. https://github.com/noprompt/meander/blob/epsilon/doc/defsyntax.md