metosin / malli

High-performance data-driven data specification library for Clojure/Script.
Eclipse Public License 2.0
1.46k stars 208 forks source link

Schema variables, aka generics #846

Open NoahTheDuke opened 1 year ago

NoahTheDuke commented 1 year ago

Hey friends,

Sometimes I have a function schema where an argument can be one of many different schemas and I want the return value to match the input schema. From reading the docs, I don't think this is currently possible, so I would like to register my desire for some way to do this.

Given this function definition and schema:

(defn simple [arg]
  (if (map? arg)
    (update arg :a (fnil inc 0))
    (conj arg :success)))
(m/=> simple [:=>
               [:cat [:or [:map [:a :int]] [:vector :keyword]]]
               [:or [:map [:a :int]] [:vector :keyword]]])

(simple {:a 1}) ; {:a 2}
(simple [:a]) ; [:a :success]

Changing the implementation continues to validate:

(defn simple [arg]
  (if (map? arg)
    [:a :success]
    {:a 2}))
(m/=> simple [:=>
               [:cat [:or [:map [:a :int]] [:vector :keyword]]]
               [:or [:map [:a :int]] [:vector :keyword]]])

(simple {:a 1}) ; [:a :success]
(simple [:a]) ; {:a 2}

@erp12 extended Malli's schema system to handle this while experimenting in their schema inference repo; maybe their design would work here?

Something like:

(m/=> simple [:=> {:schemes {'S [:or [:map [:a :int]] [:vector :keyword]]}}
               [:cat 'S]
               'S])
erp12 commented 1 year ago

Thanks for the shout out!

I agree that polymorphic schemas abstractly pop up everywhere, albeit less frequently at the edges of applications where schemas are typically used. The canonical example of a function which would logically have polymorphic schema is identity.

Our extension of the malli syntax to include schemas with parametric polymorphism was motivated by a desire for static analysis of Clojure code using malli schemas as annotations. In turn, this was used by our automatic-programming tool for synthesizing "schema safe" Clojure code from a unit test suite. The paper published at the GECCO conference can be found here, and the project is open source but not production ready.

If the malli team wants to embrace any of the schema extensions or code analysis concepts from our research, I would be happy to help port them over.