Fork me on GitHub
#meander
<
2022-07-23
>
peterh11:07:17

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]

peterh11:07:42

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.

peterh11:07:19

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.

Richie19:07:19

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

Richie19:07:19

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

peterh23:07:21

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?

peterh23:07:57

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

Richie23:07:39

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

Richie23:07:48

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/=.

peterh08:07:25

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