This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-12-29
Channels
- # announcements (2)
- # babashka (18)
- # beginners (42)
- # calva (56)
- # chlorine-clover (35)
- # clara (9)
- # clj-http (1)
- # clj-kondo (19)
- # cljs-dev (8)
- # clojure (14)
- # clojure-europe (23)
- # clojure-france (7)
- # clojure-norway (6)
- # clojure-uk (3)
- # clojurescript (37)
- # community-development (3)
- # cursive (29)
- # datomic (3)
- # emacs (10)
- # events (2)
- # fulcro (77)
- # hyperfiddle (2)
- # introduce-yourself (4)
- # joker (1)
- # lsp (40)
- # malli (52)
- # meander (7)
- # missionary (16)
- # off-topic (3)
- # pedestal (1)
- # re-frame (5)
- # reitit (38)
- # releases (1)
- # shadow-cljs (4)
- # tools-build (18)
- # tools-deps (1)
- # xtdb (8)
question: a new schema for "map or a sequence of map entries" or just an new property to :map
schema? Relates to https://clojure.org/news/2021/03/18/apis-serving-people-and-programs.
a) (m/validate [:map-like [:a :int]] [[:a 1]]) ;=> true
b) (m/validate [:map {:coerce true}: [:a :int]] [[:a 1]]) ;=> true
I'm currently thinking of going with a, as this is a special case. Both ways, it's just few lines of extra code I think
do you @nbtheduke the opinion for this?
thing is, transformers, parsers and explainers need separate code if we want to retain the original entry sequence. forcing the data to be a map allows us to reuse the current code.
for the Keyword argument functions now also accept maps
thing, we just need a map, so a simple new way to coerce the entry sequence into a map would do.
One thing to note, the input isn't a sequence of map entries, but a sequence of alternating keys and values, which can be in any order
yes. I guess this is correct:
(require '[malli.destructure :as md])
(require '[malli.generator :as mg])
(defmethod mg/-schema-generator :any [_ _] (mg/generator :string))
(-> '[& {:as m :keys [id before after]}]
(md/parse)
:schema
(mg/sample {:size 10, :seed 42}))
;(({:after ""})
; (:id "F")
; ()
; ({:after ""})
; (:before "n" :after "ai2" :id "5FI0" :id "")
; ({:after "qP3t"})
; ()
; ({:id "j"})
; ()
; (:before
; "2"
; :after
; "HW5Mn3"
; :after
; "gv9m93"
; :before
; "GVDI2b"
; :before
; "fhR"
; :before
; "F8562"
; :after
; "lS"
; :before
; "Z7y0nz"
; :before
; "7G"))
this matches the implementation, as far as i can tell! very cool
looks like you’re missing this from the test suite, i’m not sure if you’re missing it from the schema:
user=> (defn example [{:keys [id before after] :as m}] [id before after m])
#'user/example
user=> (example '(:id 1 :before 2 :after 3 :missing 4))
[1 2 3 {:id 1, :before 2, :after 3, :missing 4}]
which is to say, the bind is a destructured map, but the input can be a list of key-value pairs
weird thing, it can’t be a vector:
user=> (example [:id 1 :before 2 :after 3 :missing 4])
[nil nil nil [:id 1 :before 2 :after 3 :missing 4]]
hah yeah, it’s not really talked about anywhere, but the current version of clojure.core/destructure
allows it: https://github.com/clojure/clojure/blob/clojure-1.11.0-alpha3/src/clj/clojure/core.clj#L4434-L4439
@nbtheduke, added support for it too. starts to smell like a new :map-destructuring
Schema, which would hide the sequential part. Ugly, but works(?):
(-> '[a {:keys [b c]
:strs [d e]
:syms [f g]
:or {b 0, d 0, f 0} :as map}]
(md/parse)
:schema)
;[:cat
; :any
; [:altn
; [:map [:map
; [:b {:optional true} :any]
; [:c {:optional true} :any]
; ["d" {:optional true} :any]
; ["e" {:optional true} :any]
; ['f {:optional true} :any]
; ['g {:optional true} :any]]]
; [:args [:schema
; [:*
; [:alt
; [:cat [:= :b] :any]
; [:cat [:= :c] :any]
; [:cat [:= "d"] :any]
; [:cat [:= "e"] :any]
; [:cat [:= 'f] :any]
; [:cat [:= 'g] :any]
; [:cat :any :any]]]]]]]
amazing. thanks so much for tackling this. destructuring in clojure is really weird haha
(def Schema
(-> '[a {:keys [b c]
:strs [d e]
:syms [f g]
:or {b 0, d 0, f 0} :as map}]
(md/parse)
:schema))
(m/parse Schema [1 {:b 1, 'f 3, "e" 2, :extra 42}])
; => [1 [:map {:b 1, f 3, "e" 2, :extra 42}]]
(m/parse Schema [1 '(:c 1, , f 3, "e" 2, :extra 42)])
; => [1 [:args [[:c 1] [f 3] ["e" 2] [:extra 42]]]]
a thought experiment, should we have more argument relationship markers, e.g. :-
(is a) and :<
(a subset of)? could also go EXTREME EVIL and introduce real math symbols like :⊂
👿
(def User
[:map
[:id :uuid]
[:name :string]
[:age :int]])
;; argument is exactly User
[{:keys [id age]} :- User]
; => [:cat [:map [:id :uuid] [:name :string] [:age :int]]]
;; argument should be subset of user (mark others as optional)
[{:keys [id age]} :< User]
; => [:cat [:map [:id :uuid] [:name {:optional true} :string] [:age :int]]]
also, would be awesome if tools like #cursive and #calva would have special markers for the type hints, e.g. dim them out so it’s easier to read.
… for fully qualified keys, the key definitions could be pulled from the registry:
(mm/def ::id :uuid)
(mm/def ::name :string)
(mm/def ::age :int)
;; argument is exactly User
[{::keys [id age]}]
; => [:cat [:map ::id ::age]]
We use (still 😞 ) compojure-sweet for some of our APIs, and I see a lot of :-
in the path-params
, body....
etc...and well, personally, I found it hard to know what :-
meant etc...
in compojure-api, there is a lot of extra syntax, also the fnk
syntax. sorry for all that 🙂
I have to deal with it every day 😞 I definitely see lessons where learnt with the new improved reitit library 🙂
So, I'm not for, nor against, additional markers, I'm rather on the fence (just more stuff to learn I suppose!)
yeah, any support for inline typehints is a compromise. If IDEs would support that properly and there would be just one way to doing those, would be great.
i think i’d prefer words instead of single characters for such things. :exact
or :exactly
or :is-a
are easier to parse than :-
in my opinion. subset feels like Typescript-style structural typing, which clojure supports out of the box with open maps
I'm with Noah on this one too, I would have to translate :-
into is-a
in my head as well. Nothing wrong in being wordy, when it comes to comprehension.
ah, i understand now that :-
is supposed to be like static type declarations, that makes more sense
Is there a commonly agreed way to document the meaning of each value in a :enum
?
I don't get what you mean @UK0810AQ2
Like the map syntax, where the keys are the enumeration and optionally you could provide a properties map
(def MyEnum
[:enumn
[:small {:description "so small"} "small"]
[:medium {:description "such medium"} "medium"]])
I like the idea of enumn
.
I am wondering if there is any meaning to the keys (e.g. :small
and :medium
).
I was thinking of a slightly different semantic, [:enumn [v1 {:doc "foo}] [v2] v3]
, where the keys are the enumerations, and the syntax can be value | [value ?properties]
I prefer what you suggested @UK0810AQ2 as we don't have to duplicate the enum values
Opened an issue about this feature request https://github.com/metosin/malli/issues/613