malli

simonacca 2025-01-14T16:10:15.607669Z

Hello everyone! I have a couple of questions for you malli experts 🙂 1. How do I define a function schema for a multimethod? Say I have (defmulti wine :style), and I have in my global registry {:red [:map [:age :int]] :white [:map [:region :keyword]]} How do I define a m/=> style function schema for wine that applies the right schema based on the multimethod's dispatch function? I'm aware of :multi but I'm looking for open dispatch 2. Say that my multimethod's dispatch function is a bit more complex, like (defmulti wine (fn [w] [(:style w) (:body w)])) How do I deal with that? as I understand it, the keys in a malli registry must be either keywords or strings, a registry can't have {[:red :light] [:map [:age :int]]} p.s. I'm working in clojurescript in case that changes anything

simonacca 2025-01-15T12:54:29.064509Z

Awesome, yes it does! And this approach of mutating the :multi schema is elegant 👍 Thank you very much @ambrosebs

❤️ 1
2025-01-15T16:08:26.238709Z

I simulated mutable multimethods using immutable structures when I modeled clojure's semantics for my phd

👀 1
2025-01-15T16:08:45.040279Z

I think my advisor suggested it

simonacca 2025-01-14T16:25:31.825479Z

I came up with this

(malli/-simple-schema
   {:type :multi-dynamic
    :compile (fn [_properties [spec-key] _options]
               {:min 1 :max 1
                :pred (fn [Val] (malli/validate (spec-key Val) Val))})})
But I still have the 2nd problem

simonacca 2025-01-14T16:35:03.815549Z

indeed, but this is closed dispatch (i.e. you have to explicitly list all kv pairs), I'm looking for open dispatch based on the global registry

simonacca 2025-01-14T16:38:23.708709Z

pardon, "default registry", which I configure as a mutable registry just like in this example: https://github.com/metosin/malli?tab=readme-ov-file#mutable-registry

simonacca 2025-01-14T16:44:53.870209Z

Repro:

(ns test
  (:require [malli.core :as malli]
            [malli.registry :as malli-reg]))

(def registry* (atom {[:red :blue] :int}))

(malli-reg/set-default-registry!
 (malli-reg/composite-registry
  (malli/default-schemas)
  (malli-reg/mutable-registry registry*)))

(malli/validate [:red :blue] 123)
Fails with
; Execution error (ExceptionInfo) at (:1).
; :malli.core/invalid-schema

Kirill Chernyshov 2025-01-14T16:52:55.598139Z

what do you by "open dispatch"? Not sure if I understand how it supposes to work.

Kirill Chernyshov 2025-01-14T16:54:02.290849Z

like call validate in runtime?

simonacca 2025-01-14T16:57:55.990939Z

I mean the two schemas in your example should be looked up in the default registry instead of being provided statically inside of the :multi definition

simonacca 2025-01-14T17:22:32.010429Z

Not quite, my bad if my intent is not coming across... Let me take a different approach and explain what my goal is. I make use of function schemas ( m/=> ) in my code, and I'd like to extend this practice to multimethods as well. However the schema of the input arguments of a multimethod depend on the dispatch value, so while a multimethod has the dispatch function definition (defmulti mymulti my-dispatch-fn) and the methods definition (defmethod my-dispatch-value ...) Likewise, I'd like to define a function spec for the multimethod in a similar fashion, say: (m/=> [:multi {:dispatch my-schema-dispatch-fn}]) so that when I define a new method, I can also define a schema for it in the global registry (register! :my-method-schema-dispatchvalue [:map ...])

2025-01-14T19:10:47.466699Z

does something like multi-spec (for spec) look like what you'd need? https://clojuredocs.org/clojure.spec.alpha/multi-spec

simonacca 2025-01-14T19:12:09.883159Z

yes, exactly!

2025-01-14T20:44:02.032689Z

not aware of anything but seems like a good insight to use the registry for extensions somehow.

2025-01-14T20:45:41.829069Z

maybe the "multi-spec" schema itself could be mutated with new cases (for a theoretical malli equivalent)

2025-01-14T20:48:31.444489Z

ah, maybe you just need a function that does a functional update on a :multi in the registry. (swap! registry update :my-multi add-case ...)

2025-01-14T23:23:03.613779Z

@simon900 does this solve your problem? https://github.com/metosin/malli/pull/1162/files

cheewah 2025-01-14T23:41:15.097869Z

Hi i have a question on silencing 'special' field(s) with malli.generator/generate . Most of my malli schemas contain a :? field which is needed to pass validation, but not ideal to be generated. An example is below.

(def schema1 {:ns/MyMsg [:map {:closed true}
                         [:int32_val  :int]
                         [:? {:optional true} :any]]})
(def registry1 {:registry (malli.registry/composite-registry
                           malli.core/default-registry
                           schema1)})
(malli.generator/generate [:ref :ns/MyMsg] registry1)
; {:int32_val 1770645}
; {:int32_val 9, :? #{}}        ; <------- remove :?
; {:int32_val 3978, :? nil}     ; <------- remove :?
Is there a way to write the spec so that :? will not be generated?

2025-01-15T00:01:04.022449Z

something like [:map {:gen/fmap #(dissoc % :?)}]

👍 1
🌮 1
cheewah 2025-01-15T00:27:01.445479Z

thanks it works perfectly

🎉 1