Fun simple-check generator and postwalk

06 Jan 2014

Working on getting a better handle on the walk functions from the clojure.walk namespace I was playing with some trees (I might write about some surprises I encountered later; if the surprise is not completely due to my stupidity). I needed some large trees to work with, and decided that this was a great place to use the generators from simple-check.

What I want is a tree of a given depth and a given branching. A tree here is a map of maps of maps etc. with natural numbers at the leaves.

{:a {:b 3 :c 4} :d 5}

Getting numbers can be done by gen/nat. If you want to have control over the size of the numbers generated you can fix the size argument passed to gen/nat using gen/resize. The following

(gen/resize 100 gen/nat)

generates natural numbers up to size 100.

Since gen/map doesn’t accept the parameters I want to have specified (number of keys is the branching of my tree), I build the tree initially using vectors and tuples.

(defn gen-tree_h [depth branching]
  (if (zero? depth)
    (gen/resize 100 gen/nat)
    (gen/vector (gen/tuple gen/keyword
                           (gen-tree_h (dec depth) branching))
                branching)))

Running

(gen/sample (gen-tree_h 2 2) 3)

gives

([[:rG [[:C 65] [:42 87]]] [:J [[:6 100] [:8 75]]]]
 [[:R [[:p 35] [:8 78]]] [:U3 [[:h 19] [:q 79]]]]
 [[:g [[:8A 41] [:8f 95]]] [:wj [[:N3 87] [:E0 55]]]])

These are objects with the right structure, but (for my use) the wrong types. This was easily solved using a clojure.walk function resulting in

(defn gen-tree [depth branching]
  (let [s (first (gen/sample (gen-tree_h depth branching) 1))]
    (walk/prewalk #(if (and (vector? %) (vector? (first %))) (into {} %) %) s)))