reiddraper/simple-check — pull request #25 by reiddraper (2013-10-10 02:10:45+00:00)
Title: Compose shrinks when creating generators

This is a large (and I think entirely backward compatible) change to the
way generators and shrinking works. Previously generators would generate
random values of type A. Whatever type ended up being generated would be
used to control how shrinking was done. This was a problem when you
created implicit constraints in the generator, that were not seen in the
_type_ of the generated value. For example, multiplying an integer
generator by two will always result in an even value. Further, choosing
a random element from the vector [:foo :bar :baz] should shrink to one
of those elements if the property fails. It should not see :foo, and
then shrink that to :f. The fix is to change generators from generators
of A's, to generators of shrink trees of A's. The top of the tree is the
generated value, and the children are the first layer of shrinking. This
tree is lazy. This allows generators to build on the shrink tree of their
parent during generator composition. Some examples of what is now possible:

;; will only generator :foo, and will never shrink
(gen/return :foo)

;; will generate a non-empty vector of integers, and then
;; randomly choose one element. Shrinking will shrink toward
;; an earlier element in the vector
(gen/bind (gen/such-that not-empty (gen/vector gen/int))
gen/elements)

;; will choose an element from the vector, and shrink
;; toward choosing an earlier element
(gen/elements [:foo :bar :baz])

;; will generate powers of two, that shrink to smaller powers
;; of two
(gen/fmap #(long (Math/pow 2 %)) gen/nat)

Fixes #22.