This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-20
Channels
- # aleph (1)
- # announcements (1)
- # aws (11)
- # babashka (117)
- # beginners (34)
- # calva (13)
- # cider (3)
- # clj-commons (8)
- # clj-kondo (24)
- # clj-yaml (36)
- # cljsrn (46)
- # clojure (50)
- # clojure-australia (5)
- # clojure-europe (239)
- # clojure-nl (3)
- # clojure-norway (3)
- # clojure-spec (16)
- # clojurescript (25)
- # core-typed (20)
- # cursive (41)
- # datahike (1)
- # datalevin (1)
- # datomic (17)
- # fulcro (27)
- # hyperfiddle (35)
- # introduce-yourself (1)
- # jobs (4)
- # lsp (20)
- # malli (8)
- # meander (8)
- # nbb (1)
- # off-topic (31)
- # parinfer (9)
- # pathom (3)
- # portal (2)
- # re-frame (20)
- # react (2)
- # reagent (8)
- # releases (1)
- # remote-jobs (4)
- # scittle (2)
- # shadow-cljs (8)
- # slack-help (4)
- # sql (30)
- # squint (3)
- # tools-deps (34)
- # xtdb (21)
I'm trying to use spec to build a generator for valid destructure bindings. I'm starting with the specs in clojure.core.specs.alpha
.
(s/def ::seq-binding-form
(s/and vector?
(s/cat :forms (s/* ::binding-form)
:rest-forms (s/? (s/cat :ampersand #{'&} :form ::binding-form))
:as-form (s/? (s/cat :as #{:as} :as-sym ::local-name)))))
Generating ::seq-binding-form
values struggles because it's just generating random vectors that hopefully satisfy the s/cat
. This seems to get fixed with (gen/fmap vec ...)
:
(s/def ::seq-binding-form
(s/with-gen
(s/and vector?
(s/cat :forms (s/* ::binding-form)
:rest-forms (s/? (s/cat :ampersand #{'&} :form ::binding-form))
:as-form (s/? (s/cat :as #{:as} :as-sym ::local-name))))
#(gen/fmap
vec
(s/gen
(s/cat :forms (s/* ::binding-form)
:rest-forms (s/? (s/cat :ampersand #{'&} :form ::binding-form))
:as-form (s/? (s/cat :as #{:as} :as-sym ::local-name)))))))
Unfortunately, the version using gen/fmap
now usually throws a stackoverflow exception. However, I noticed that if I ignore the vector requirement for ::seq-binding-form
, then the stack overflow exception goes away.
(s/def ::seq-binding-form
(s/cat :forms (s/* ::binding-form)
:rest-forms (s/? (s/cat :ampersand #{'&} :form ::binding-form))
:as-form (s/? (s/cat :as #{:as} :as-sym ::local-name))))
Is there a way to prevent and stackoverflow exceptions and have it generate a vector?It looks like spec2 might have better support for this. I don't have any real reason to stick with spec1, so I'll see if I can get this working with spec2.
I don't know about conforming, but I'll take a look
I was checking out spec2 based off this previous thread, https://clojurians.slack.com/archives/C1B1BB2Q3/p1650425212914829?thread_ts=1650424802.839689&cid=C1B1BB2Q3
giving it a try!
I don't think that solves this use case. It still doesn't generate ::seq-binding-form
as a vector. It does convert it if I conform the value, but I think it's worth trying spec2
It's totally possible I'm doing it wrong. My attempt was:
(s/def ::seq-binding-form
(s/and
(s/cat :forms (s/* ::binding-form)
:rest-forms (s/? (s/cat :ampersand #{'&} :form ::binding-form))
:as-form (s/? (s/cat :as #{:as} :as-sym ::local-name)))
(s/conformer vec)))
the specs need to be updated to have this work with spec 2
It works!
Just to follow up, test.check
is magic. For the right problems, it finds tricky use cases that I would never think of.
> (let [[ & [ & [& [& [& [& hi]]]]]] [42]]
hi)
(42)
> (let [[& {:as m}] [:a 42]]
m)
{:a 42}