meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
phronmophobic 2021-02-25T01:09:54.031600Z

I keep wanting to write patterns with different sets of unbound logic variables in m/or statements. Is that an anti pattern? Is there a workaround? My previous example was one of those cases, but another is similar to core.match:

(let [v [[1 2]]]
  (match [v]
    [[[3 1]]] :a0
    [[([1 a] :as b)]] [:a1 a b]))
;=> [:a1 2 [1 2]]

phronmophobic 2021-02-25T01:11:51.033800Z

Does meander expose a way to detect unbound logic variables in a pattern? If so, I could also write a macro that finds the superset of logic variables for each pattern and wraps each pattern with (m/let [v1? nil v2? nil] so that each pattern has the same set of unbound logic variables

william 2021-02-25T01:30:28.034Z

I'm also very interested in having disjoint sets of logical variables in a m/or clause, or at least understanding better why that's not possible

phronmophobic 2021-02-25T01:55:48.034200Z

this seems to work:

(m/defsyntax mor [& patterns]
  (let [vars
        (into []
              (comp
               (map r.syntax/parse)
               (map r.syntax/logic-variables)
               (map #(map r.syntax/unparse %))
               (map set))
              patterns)
        all-vars (into #{} cat vars)]
    `(m/or
      ~@(for [[pvars pattern] (map vector vars patterns)
              :let [missing (clojure.set/difference all-vars pvars)]]
          (if (seq missing)
            (let [bindings
                  (into []
                        cat
                        (for [v missing]
                          [v nil]))]
              `(m/let ~bindings
                 ~pattern))
            pattern)))))

;; usage
(m/find
  {:b 2}
  (mor {:a (m/some ?a)}
       {:b (m/some ?b)})
  [?a ?b])
;; [nil 2]

(m/find
  {:a "A"}
  (mor {:a (m/some ?a)}
       {:b (m/some ?b)})
  [?a ?b])
;; ["A" nil]

phronmophobic 2021-02-25T01:56:10.034400Z

not sure if this is a good idea or not

noprompt 2021-02-25T06:51:25.042300Z

The reason meander doesn’t allow for disjoint unbound logic variables in an or are for the following reasons: 1. For match, find, and search I don’t have an answer to the question “what do I bind these to?” Perhaps, a special unbound value? In other words, there is no semantic. There could be a semantic but I don’t know what it should be. In the case of rewrite I think relaxing this restriction is fine because a semantic can be defined for using an unbound logic variable on the right hand side: it fails. In fact, this is the semantic zeta will use where you can also use or on the right side making this actually useful. 2. Meander borrowed a lot of ideas from existing pattern matchers. Racket’s match is one of them and, in particular, I borrowed the or semantics from them.

noprompt 2021-02-25T07:00:37.048Z

I wouldn’t say wanting different sets of unbound logic variables is an “anti pattern” but I surmise that the problem is with the data. If the model has lots of ambiguity in it, so will your code. Typically, I will try to eliminate the ambiguity prior to doing heavy transforms.

noprompt 2021-02-25T07:06:41.051400Z

I’m up for relaxing variable restrictions use or provided a semantics or an idea for an implementation. We can use meta on the macro forms as well to pass options.

^{::m/disjoint-variables {:unbound nil}} (m/find ,,,)

phronmophobic 2021-02-25T07:07:30.052500Z

did you see the syntax I tried at https://clojurians.slack.com/archives/CFFTD7R6Z/p1614218148034200?thread_ts=1614215511.033800&cid=CFFTD7R6Z ?

noprompt 2021-02-25T07:07:30.052600Z

But I won’t automatically default to nil myself because I think that’s rude. 🙂

noprompt 2021-02-25T07:07:50.053300Z

Yes, I saw that. This topic has come up before.

phronmophobic 2021-02-25T07:08:02.053700Z

yea, totally makes sense for the default to disallow it

phronmophobic 2021-02-25T07:08:46.054300Z

In my case, I'm using it to extract data from an API, so I can't really change the API

phronmophobic 2021-02-25T07:09:18.055Z

It's possible that I'm missing using meander and should be using something like core.match

noprompt 2021-02-25T07:09:25.055200Z

Ah, yeah, many APIs have this great feature “optional data”. Its really cool…

noprompt 2021-02-25T07:10:23.056100Z

You’re not misusing the library.

😌 2
noprompt 2021-02-25T07:11:10.057Z

One of the reasons I started this project was because I did not like core.match.

😁 2
noprompt 2021-02-25T07:12:07.058500Z

Let’s solve this problem. There’s at least 2 other people that want a solution.

phronmophobic 2021-02-25T07:13:06.060200Z

more or less, I'm trying to find a way to idiomatically deal width a values like results where either you have 1. a success, something like {:type result :val {:a :some-value}} 2. a failure, something like {:type :err :msg "You're did it wrong!"}

noprompt 2021-02-25T07:13:53.061300Z

My best shot is enabling this via meta data on the form. It is probably the easiest to achieve (for me) without spending too much time. You’re new here but I’ve really been trying to focus on zeta , only fixing bugs, etc.

phronmophobic 2021-02-25T07:14:04.061700Z

or some equivalent to https://clojure.org/guides/spec#_multi_spec

noprompt 2021-02-25T07:14:53.062500Z

Is there something off putting about having two clauses?

noprompt 2021-02-25T07:15:43.064Z

(m/match M
  {:type :result ,,,}
  A

  {:type :err ,,,}
  B)

noprompt 2021-02-25T07:16:07.064400Z

I’m guessing theres more to the story?

phronmophobic 2021-02-25T07:17:18.065600Z

well, in my case, the return value is surrounded by a bunch of boilerplate that I'm also extracting values from, but it's easy enough to split it up into two matches (ie. two steps)

phronmophobic 2021-02-25T07:18:14.066700Z

My use case is currently already solved well by meander, I was just wondering if there was an already existing approach that was more idiomatic

noprompt 2021-02-25T07:18:43.067300Z

FWIW another “trick” you can apply is to grab all the other stuff as usual and process the inner stuff with m/cata.

🤯 1
noprompt 2021-02-25T07:19:45.068700Z

{:other ?stuff
 :around {:in ?here}
 :random-junk [(m/cata !xs) ...]
{:stuff ?stuff, :here ?here, :no-longer-junk !xs}

noprompt 2021-02-25T07:20:33.069400Z

m/cata is like recur but over the whole system and how you transform nested stuff using the same set of rules.

phronmophobic 2021-02-25T07:21:29.070500Z

very cool. I've been using meander to extract data from some verbose xml and it's been great.

phronmophobic 2021-02-25T07:21:53.071200Z

Once I figured out how to match on unordered lists, it worked like a charm

phronmophobic 2021-02-25T07:22:48.072600Z

the question about m/or is because now I just want to use meander to improve other parts of the code

noprompt 2021-02-25T07:23:18.073Z

Take a look at m/cata. I think there’s some documentation that explains it. It can be very effective at solving icky problems like these. Also, I think would like to make people happy and solve the disjoint variable problem. If the meta thing will work, I’ll make a patch soon. If there’s a better idea, I’m open to it.

noprompt 2021-02-25T07:23:56.073400Z

I’m glad you’re enjoying it and it is helping you. 🙂

😁 1
noprompt 2021-02-25T07:25:17.075100Z

I do need to sign off for the night but I’m down to chat more about this tomorrow; get input from others.

phronmophobic 2021-02-25T07:25:40.075600Z

Thanks for your help. Have a great night!

noprompt 2021-02-25T07:25:52.075900Z

Likewise!