malli icon indicating copy to clipboard operation
malli copied to clipboard

New destructuring in Clojure 11: Keyword argument functions now also accept maps

Open NoahTheDuke opened this issue 3 years ago • 4 comments

As discussed on slack, Clojure now supports destructuring maps as key-value pairs in parameter lists: [& {:as m :keys [id before after]}] can be used as both (f {:id 1 :before 2 :after 3}) and (f :id 1 :before 2 :after 3). To use this when writing a schema requires doubling up on the definition:

(def f
  (m/schema
    [:=>
     [:cat
      [:or
       [:and
        [:map
         [:id qualified-keyword?]
         [:before {:optional true} fn?]
         [:after {:optional true} fn?]]
        [:fn (fn [{:keys [before after]}] (or before after))]]
       [:and [:catn
              [:id [:cat [:= :id] qualified-keyword?]]
              [:before [:? [:cat [:= :before] fn?]]]
              [:after [:? [:cat [:= :after] fn?]]]]
        [:fn (fn [[_ & args]] (pos? (count args)))]]]]
     :any]))

NoahTheDuke avatar Dec 27 '21 18:12 NoahTheDuke

Indeed, we need a better way for this.

ikitommi avatar Dec 27 '21 21:12 ikitommi

could compress that into:

(def f
  (m/schema
   [:=>
    [:cat
     [:and
      [:map-like
       [:id qualified-keyword?]
       [:before {:optional true} fn?]
       [:after {:optional true} fn?]]
      [:fn (fn [{:keys [before after]}] (or before after))]]]
    :any]))

ikitommi avatar Dec 29 '21 11:12 ikitommi

... currently working an a (schematized) destructuring support for malli, generating:

(ms/schema '[a b [c & {:keys [c e] :as ce}] & {:keys [f g] :as fg}])
;[:cat
; :any
; :any
; [:maybe
;  [:cat
;   [:? :any]
;   [:altn
;    [:map [:map 
;           [:c {:optional true} :any] 
;           [:e {:optional true} :any]]]
;    [:args [:* [:alt 
;                [:cat [:= :c] :any] 
;                [:cat [:= :e] :any]]]]]]]
; [:altn
;  [:map [:map 
;         [:f {:optional true} :any] 
;         [:g {:optional true} :any]]]
;  [:args [:* [:alt 
;              [:cat [:= :f] :any] 
;              [:cat [:= :g] :any]]]]]]

... with that, you would get this schema out from your function:

(ms/schema '[& {:as m :keys [id before after]}])
;[:cat
; [:altn
;  [:map [:map 
;         [:id {:optional true} :any] 
;         [:before {:optional true} :any] 
;         [:after {:optional true} :any]]]
;  [:args [:* 
;          [:alt 
;           [:cat [:= :id] :any] 
;           [:cat [:= :before] :any] 
;           [:cat [:= :after] :any]]]]]]

would that be useful enough for your actual case?

ikitommi avatar Dec 29 '21 11:12 ikitommi

#606

ikitommi avatar Dec 29 '21 21:12 ikitommi