Yes, I could show you a simple example:
Let's create our own 78 digits long string type:
(def hex-digit (set "0123456789"))
(defn hex-digit? [x] (contains? hex-digit x))
(defn hex-str? [s] (every? hex-digit? (seq s)))
(s/def ::hash (s/and hex-str? #(= (count %) 78)))
::hash is now registered, now we go to the REPL:
(s/valid? ::hash "23179372")
;;=> false
(s/valid? ::hash "nope93721907914920047210715459933122004671648400678953445710500236944435987060")
;;=> false
(s/valid? ::hash "231793721907914920047210715459933122004671648400678953445710500236944435987060")
;;=> true
That's cool, but we want to generate too:
(defn hex-str-gen [n]
(let [digit (g/elements hex-digit)]
(g/fmap clojure.string/join (g/vector digit n))))
(s/def ::hash (s/with-gen (s/and hex-str? #(= (count %) 78)) #(hex-str-gen 78)))
We extended our ::hash spec with a generator function, so we can do this now:
(g/generate (s/gen ::hash))
;;=> "310584715385467847758653938894742415543975445356609397864862925839413265904779"
(+ Pro tip: you could spec functions too)
Learn more about spec here: https://clojure.org/guides/spec