I was running into a mysterious bug in my program, which populates generations of growth using mapcat and an atom. I was hitting an error where, on whatever the last designated step of the population growth, it was only parsing the first four items (seriously throwing off my population count). I examined my code closely and then started looking into mapcat, where finally I found the single note at the bottom of the documentation here: https://clojuredocs.org/clojure.core/mapcat. Using that as inspiration, I solved my problem by adding a doall
that forced evaluation. My question is, why is there a magic number 4 with mapcat, and is there some way I should have known about that?
My code for anyone interested:
(defn create-generations
"Create `num-generations` generations for `username` base-name; if `num-generations` is 0, no action is taken"
[username num-generations]
(when (< 0 num-generations)
(let [parents (create-couple {:username username}) ;; create-couple returns a tuple [person-a person-b]
after-parents 2
CURRENT-COUPLES (atom parents)]
(doseq [n (range after-parents (inc num-generations))]
(log/info (str "Adding " (* 2 (count @CURRENT-COUPLES)) " people for generation " n
" :\n\t" (prn-str @CURRENT-COUPLES)))
(let [new-couples (doall (mapcat ;; << right here, without the doall, is where it was short-circuiting after 4
(fn mapcat-generations [[father-id mother-id]]
(log/info (str "Creating couple:" (prn-str {:fa father-id :mo mother-id})))
(create-couple {:username username
:father-id father-id
:mother-id mother-id
:generation-n n}))
@CURRENT-COUPLES))]
(reset! CURRENT-COUPLES new-couples))))))