Fork me on GitHub
#meander
<
2022-07-31
>
peterh00:07:04

I try to implement a pattern on a set where I need to match the same subset twice: - 1) the subset is a singular element of the parent set - 2) the elements of the subset are elements of the parent set Example: #{ y #{x y} x } (the subset here being #{x y} of course) It should work with any given subset, not a specific one. I thought about something like this:

(m/find
  [['a 'b] 'a 'b]
  [?x & ?x] :yes)
but using set patterns, like:
(m/find
  #{'b #{'a 'b} 'a}
  #{?x ^& ?x} :yes)
But this does not work, because ?x appears twice in the set and Clojure doesn’t seem to recognize this “fake” rest pattern in sets: ^& Can I use something like #{?x ^& ?y} instead and somehow unify the two logic variables similar to (== ?x ?y) in Clojures core.logic? Or is there any other way to solve this in Meander, if it is possible at all?

peterh20:07:57

Okay, so I just found out that I can do this with maps:

(m/find {'b 0, {'a 0, 'b 0} 0, 'a 0}
    {?x _ & ?x} ?x)
;=> {a 0, b 0}
This is pretty nice and it makes me believe that it should actually - in principle - work with sets the same way, since sets in Clojure are just (as far as I know) maps that map each element to itself (please correct me if I’m wrong). So the only reason why it does not work is that Clojure has no “real” rest syntax for sets, right? Any workarounds?

peterh21:07:13

(this is just a note to myself as I try to figure this out, maybe it helps others too, so I post it here) The example in my last post only works if there are no further keys in the outer map, because the ?x will try to unify the exact same map:

(m/find {'b 0, 'c 2, {'a 0, 'b 0} 0, 'a 0}
    {?x _ & ?x} ?x)
;=> nil  (because of 'c 2)
The following example works because the map pattern in the rest match is only matched as a submap (same with sets):
(m/find {'b 0, 'c 2, {'a 0, 'b 0} 0, 'a 0}
    {{'a 0, 'b 0} _ & {'a 0, 'b 0}}
    :true)
;=> true
Somewhere I have seen that you can have multiple rest patterns, so with logic variables it can be done like this instead:
(m/find {'b 0, 'c 2, {'a 0, 'b 0} 0, 'a 0}
    {?x _ &0 ?x &1 _} ?x)
;=> {a 0, b 0}