noprompt / meander

Tools for transparent data transformation
MIT License
918 stars 55 forks source link

Allow more than one rest pattern (& pattern) to appear in supported patterns #180

Closed noprompt closed 3 years ago

noprompt commented 3 years ago

This patch permits sequential patterns to use more than one rest pattern enabling the following possibilities (among many more).

Seq pattern matching

(m/find (range 1 11)
  (1 2 & ?rest-1 4 5 & ?rest-2 9 10)
  [?rest-1 ?rest-2])
;; => [(3) (6 7 8)]

Seq pattern matching with vector pattern substitution

(m/rewrite (range 1 11)
  (1 2 & ?rest-1 4 5 & ?rest-2 9 10)
  [& ?rest-2 :A :B :C & ?rest-1])
;; => [6 7 8 :A :B :C 3]

Map matching

(let [m {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}]
  (m/find m
    {:g 7 :h 8 :i 9
     &a {?k (m/pred even?) & '{} :as ?m1}
     &b ?m2}
    [?k ?m1 ?m2]))
;; =>
[:f {:f 6} {:e 5, :c 3, :b 2, :d 4, :a 1}]

Map substitution

(let [?m1 {:a 1 :b 2}
      ?m2 {:c 3 :d 4}
      ?kvs1 [[:e 5] [:f 6]]]
  (m/subst {&1 ?m1
            &2 ?m2
            &3 ?kvs1
            &4 [[:g 7] [:h 8] [:i 9]]}))
;; =>
{:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9}

Whats new on the surface is slight change in syntax: the rest operator is a symbol with a name matching the regex &.*. This is to get around the limitation of duplicate map keys.

In terms of implementation, there is a new node type :merge which is created during map parsing.

jimmyhmiller commented 3 years ago

This looks awesome!