Fork me on GitHub
Franco Gasperino17:06:11

Working with spec, im writing a custom generator to produce UUID values. Experimenting with this, i've come up with the following:

(def gen-uuid (spec/gen 
                (into [] 
                  (take 1000
                    (repeatedly #(str (java.util.UUID/randomUUID)))))))
=> ; Execution error (NullPointerException) at java.util.regex.Matcher/getTextLength (
; null
However, the form works as expected outside the gen call. What am i missing?


what's the docstring of spec/gen?

Franco Gasperino17:06:02

the argument must be a spec itself. Maybe i'm confused that a set can be used as an argument


there is no set in your code

Franco Gasperino17:06:15

There is in the clojure spec guide:

First example has the following:
(def kw-gen (s/gen #{:my.domain/name :my.domain/occupation :my.domain/id}))
(gen/sample kw-gen 5)
I was unaware of its behavior here


yes, but your into call is constructing a vector

Franco Gasperino17:06:39

correct. my confusion is how a set behavior differs. I'm missing something fundamental about set behavior as a spec, compared to other sequences

Alex Miller (Clojure team)17:06:49

sets are specs of enumerated values

Franco Gasperino17:06:31

alright. ill noodle on the implications of that

Franco Gasperino17:06:41

(def uuid-regex
  (re-pattern #"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"))

(spec/def ::uuid?
   (spec/and string? #(re-matches uuid-regex %))
   #(spec/gen (into #{} (take 100 (repeatedly (fn [] (str (java.util.UUID/randomUUID)))))))))

(spec-gen/sample (spec/gen ::uuid?))
This works when the vector is replaced with a set

Franco Gasperino17:06:31

I have a related question regarding custom generators


you may also want to check out the built in uuid generate in test.check ( that spec uses as the generator for the clojure.core/uuid? predicate

Franco Gasperino17:06:14

(def uuid-regex
  (re-pattern #"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"))

(spec/def ::uuid?
    (spec/and string? #(re-matches uuid-regex %))
      (into #{}
       (take 100
        (repeatedly (fn [] (str (java.util.UUID/randomUUID)))))))))

(defn truncate-uuid [x] (apply str (take-last 12 x)))

(spec/fdef truncate-uuid
   :args (spec/cat :uuid ::uuid?)
   :ret string?)

;; clojure.spec.test.alpha :as spec-test
(spec-test/check `truncate-uuid)

=> ({:spec
  #object[clojure.spec.alpha$fspec_impl$reify__2525 0x4d86324 "clojure.spec.alpha$fspec_impl$reify__2525@4d86324"],
  :clojure.spec.test.check/ret {:result true, :pass? true, :num-tests 1000, :time-elapsed-ms 45, :seed 1623952390632},
  :sym eventflow.schema/truncate-uuid})

Franco Gasperino17:06:48

in this case, is the check, which is leveraging the custom generator, only supplying check with values coming from the generator?

Franco Gasperino17:06:03

or will it create produce values matching the spec predicate which are not produced by the generator as part of the check?

Franco Gasperino18:06:18

A better illustration may be from "Custom Generators"


you are asking if the spec will try "negative" cases?

Franco Gasperino18:06:56

yes, when a custom generator is applied within the spec


no, custom generator or not


a spec says the result is defined over some set of inputs, and says nothing about the result over inputs not in the that set

Franco Gasperino18:06:24

how would you suggest i reason about a spec for the following:

(defn in?
  "Return true if x is in coll, false otherwise."
  [coll x]
  (if (some #(= x %) coll) true false))

(spec/fdef in?
  :args (spec/cat :coll coll? :x any?)
  :ret boolean?)

(spec-test/check `in?)

Franco Gasperino18:06:22

the generator works. can i be certain that the affirmative case returning true is exercised without a custom generator? If not, how can i apply a custom generator and then affirm the inverse?

Alex Miller (Clojure team)18:06:51

one technique is to use a custom generator that you know generates both cases

Franco Gasperino18:06:55

or maybe more terse, how do i associate the argument :coll with :x both in the true and false case within the generator


no, you'll want a custom generator if you want to spec that

Alex Miller (Clojure team)18:06:35

s/fdef can have a :fn spec that receives both the conformed input spec and the conformed ret value

Alex Miller (Clojure team)18:06:18

for something like this, it's helpful to make a generator that generates the :x, then builds the :coll to contain it

Franco Gasperino18:06:45

ok. i see the :fn kwarg now in fdef


I would create a custom generator using, uh, I forget the test.check stuff, but there are combinators that say "generate something by choosing one this collection of generators, and generate from that" and have a generator that is completely random in coll and x


and a generator that generates a random coll and chooses an x from it

Alex Miller (Clojure team)18:06:13

gen/fdef is a useful combinator for the latter (and gen/bind for the former)

Franco Gasperino18:06:00

thanks for the feedback. quite helpful

Franco Gasperino18:06:37

on the philosophy of spec and test, do you only write a spec for testing, not conforming, as part of your flow, or only where necessary / appropriate?

Franco Gasperino18:06:37

in many spots, it can add a significant amount of code overhead when a form can be proven in the repl. what do you find works best on teams?

Alex Miller (Clojure team)18:06:34

I am judicious in where I write them - mostly for tricky low-level stuff where it's best to generate large input sets for verification, or for api-level contracts

Alex Miller (Clojure team)18:06:46

where instrumentation can be useful during dev

Franco Gasperino18:06:17

do you have a preferred path regarding external data on the application boundaries? Conform during runtime? Generators for testing?


I am trying to destruct map

(let [keys [:my_id (:myid input)]]
     _ (println keys))


i want to rename value from :myid to :my_id


"Destructuring is a way to concisely bind names to the values inside a data structure."


it is not a way to modify datastructures


(the quote is first line in the guide linked above)


making a calendar app in clojurescript... any recommendations on how I can find the number of days in a month programmatically, and the day of the week for a given date?

Michael Stokley18:06:53

i'd recommend using a date and time library. moment.js, for example

Michael Stokley18:06:00

it's more difficult than i'd ever want to mess with, especially in the context of robust third party libs


Right on. I have not worked with bringing in third party libs to CLJS at all.. gotta learn how to do that

Michael Stokley18:06:29

looks like there are cljs libs, too


cljs-time seems fine, but if you are thinking of pulling in a js library to interop on, I'd advise against moment.js. It's deprecated and the reasons why are documented on their website


Rockin. Tryin out cljs-time now.. it seems like it has all the fxns I would need to make a simple cal app


date-fns is a date library that is more functionally oriented and more modular, if you wanna go the js route

👍 2

So shadowcljs doesn't support cljsjs ... which makes sense because it's NPM based... gotta figure out how to bring the dependency in


thank you... scanning now


also asked in shadow-cljs... If a library exists in NPM such as "date-fns" do I still need to include it in the `:dependencies [[]]`  key in shadow-cljs.edn?


Oh I see.. npm install date-fns covers the dependencies. ^.^


Without dependencies you can do something like

(require '[ :as gdate])
(gdate/getNumberOfDaysInMonth 2021 0)


Google Closure Library has incredible amount of things in it.


Oh that's sweet. That's probably the way to go


Hmmm. I don't know enough about cljs/js interop yet to know how to get the weekday for a given date


I tried something like (. weekDay (gdate/Date 2023 1))


but that doesn't work ... I am probably missing something vital


(.getWeekday (gdate/Date.))


Not on a computer anymore so can’t verify :/


Thanks 😃 I am trying (.info js/console (.-getWeekday (gdate/Date. 2023 1 1))) but I get a function definition printed in the console ;/


.Weekday works but the hyphen does not


.getWeekday instead of .-getWeekday


super ninja coder skills don't need no computing devices ^.^


Ooh yeah the hyphen is used for property access, without is for method invocation


Hey, sorry to bother you. I try to remove forms from a tree structure. My solution is ... let's call it messy, so I just wanted to ask some experts if there is a more concise way of doing this?

(defn remove-tree [pred tree]
    (loop [n '()
           [h & rst] tree]
      (let [e (if (pred h)
                (conj n
                 (if (list? h)
                   (remove-tree pred h)
        (if rst
          (recur e rst)

;; simple example for testing: remove expr begining with +
     (fn [x]  (and (list? x) (= '+ (first x))))
       (- 1 1 (+ 1 1))
       (+ 1 2)
       (- 2 3 (- 1 1))))
   ;; => (((1 1 -) 3 2 -) 3 (1 1 -) -)
Furthermore, I still have to reverse the result 🙈 I also tried walk but I couldn't figure out a solution with it.


you could do this with, but I like using zippers!

(require '[ :as z])
(defn zip-walk
  "Depth first walk of zip. edit each loc with f"
  [zip f]
  (loop [zip zip]
    (if (z/end? zip)
      (z/root zip)
      (recur (-> (z/edit zip f)

(defn tree-zip [obj]
  (z/zipper list?
            (fn [node children]
              (into '() (remove #{::remove} children)))

(defn remove-tree [pred tree]
  (zip-walk (tree-zip tree)
            (fn [obj]
              (if (pred obj)


Awesome, thanks for the input


zippers work really well for functionally editing trees


walk works too

 (fn [item]
   (if (list? item)
      (fn [x]
        (if (and (list? x)
                 (= '+ (first x)))
   (- 1 1 (+ 1 1))
   (+ 1 2)
   (- 2 3 (- 1 1))))
The main thing is you just have to keep straight the list you are splicing vs the list your are looking for to splice out


(that mapcat can just be a filter)


Oh, very cool. Thank you. I had (tbh still have) some troubles to wrap my head around how walk works, but this helps a lot


(doseq [o 2
	    d (range 1 31)
  :let [c (mod (+ d o) 7)]]
  	   (println d [c c]))
is giving me a "Don't know how to create ISeq from java.lang.Long" ... but if I remove the o 2 and hardcode in a (+ d 2) it works what am I doing wrong with doseq?


(ins)user=> (doseq [:let [o 2] d (range 1 31) :let [c (mod (+ d o) 7)]] (println d [c c]))
1 [3 3]
2 [4 4]
3 [5 5]
4 [6 6]
5 [0 0]
6 [1 1]
7 [2 2]
8 [3 3]
9 [4 4]
10 [5 5]
11 [6 6]
12 [0 0]
13 [1 1]
14 [2 2]
15 [3 3]
16 [4 4]
17 [5 5]
18 [6 6]
19 [0 0]
20 [1 1]
21 [2 2]
22 [3 3]
23 [4 4]
24 [5 5]
25 [6 6]
26 [0 0]
27 [1 1]
28 [2 2]
29 [3 3]
30 [4 4]


are there limitations on what I can put in the :let clause?


@sova doseq expects you to provide sequences (rather: seqable object) in the right hand binding. 2 is not a seqable.


I see. (repeatedly 2) also did not work ;x


try (repeat 2)


(btw, that doseq won't step in that case)


what you probably wanted: (let [o 2] (doseq [d ...]))


i'll get back to you on if i solved the halting problem or not :rolling_on_the_floor_laughing:


how do you know if solving the halting problem will ever stop and when to stop trying?


beginnings and ends are a duality, for every end there must be a beginning. it's a simple boolean 😛


actually that still doesn't solve the halting problem... some beginnings don't end in a reasonable amount of time. hit the brake and if it doesn't do anything, eject? =D


all those runaway computations must get tired eventually


hello, i have a 2 dimensional array m x n like this 1 2 3 4 ..... m 1 1a 2a 3a 4a .... ma 2 3 4 ... n every element in the array has it own range, eg. 1a (-0.1 + 0.15 ), 2a ( -0.2 + 0.4), then how can i iterate all possible values for this array then do sth for each possible value for -0.1 ... +0.15 for -0.2 ... + 0.4

about m x n nested for loops


one step is 0.01, so like this: -0.1 -0.09 -0.08 ... 0, 0.01, 0.02....0.15


@U11BV7MTK every element's range is different


How many values are in the range (-0.1 +-0.15)?


0.01 is a step, -0.1 -0.09 -0.08 like this