meander

peterh 2022-07-23T11:04:17.553579Z

Is there a shorter or more idiomatic way in Meander to constrain a matching set to only include specific elements than by using the empty? predicate?

(let [f (r/find
          #{'a ^& (m/pred empty?)} :yes)]
  [(f #{'a 'b}) (f #{'a})])
;=> [nil :yes]

;; this will not work:
(let [f (r/find
          #{'a ^& #{}} :yes)]
  [(f #{'a 'b}) (f #{'a})])
;=> [:yes :yes]

peterh 2022-07-25T08:43:25.440959Z

Yeah, I don’t know how to further match on it. The ?x in your example only matches the whole expression. Basically I would like to use logic variables inside the set pattern, like #{:a ?x} and then match on that, but at the same time the set should not contain more than 2 items (in this example).

peterh 2022-07-24T23:34:21.457769Z

I haven’t thought about this, but the issue I see with your suggestions is that I cannot use a pattern in the predicate, just an ordinary Clojure expression. Or is there a trick that would still allow me to do so?

peterh 2022-07-24T23:35:57.257169Z

By pattern I mean a Meander pattern with logic variables, etc.

Richie 2022-07-24T23:55:39.930779Z

(mr/match #{:a}
          (mr/and (mr/pred #(= #{:a} %)) ?x) [:one ?x]
          _ :two)

Richie 2022-07-24T23:56:48.361989Z

This may not address your concern. I'm not sure if you're saying that you don't know how to further match on it or if you're pointing out that I'm using clojure.core/=.

peterh 2022-07-23T11:19:42.575699Z

I see now why the second idea does not work: in the macroexpansion, it checks for #{} to be a subset of the rest of the input set, which of course will be the case for any set. With the predicate solution, it will only apply the predicate to the rest of the set to check if it is empty. Maybe I can do something with defsyntax here to make it shorter, have to learn how this works.

peterh 2022-07-23T11:36:19.917929Z

Okay, so I can do it like this:

(m/defsyntax ∅ []
  `(m/pred empty?))

(let [f (r/find
          #{'a ^& (∅)} :yes)]
  [(f #{'a 'b}) (f #{'a})])
;=> [nil :yes]
Although I feel like this may be a more common thing and would have a built-in solution, but I couldn’t find anything yet.

Richie 2022-07-23T19:18:19.764209Z

(mr/match #{:a :b}
  (m/pred #(= #{:a} %)) :one
  _ :two)
;; :two

Richie 2022-07-23T19:20:19.410589Z

(let [x #{:a :b}]
  (mr/match x
    (m/guard (= x #{:a})) :one
    _ :two))
;; :two