我认为 {{clojure.core/for}} 的语法很适合与 test.check 的组合符号一起使用。例如:
(defn gen-even-subset
"返回一个生成器,该生成器生成给定元素的偶数卡迪纳尔性子集"}
[elements]
(gen/for [bools (apply gen/tuple (repeat (count elements) gen/boolean))
:let [true-count (->> bools (filter identity) (count))]
:when (even? true-count)]}
(->> (map list bools elements)
)
这结合了 {{fmap}}、{{bind}} 和 {{such-that}} 的功能,使用了熟悉的语法。
这里的一个缺点是,当多个生成器独立时,可能会倾向于使用多个子句,从而导致在 {{gen/tuple}} 简化且可能更容易缩小时,使用 {{gen/bind}}。针对此问题的一个方法是添加一个额外的支持子句,可能称为 {{:parallel}},它使用 {{:let}} 的语法来提供 {{gen/tuple}} 的功能。
(gen/for [:parallel [n1 gen/nat
n2 gen/nat]
:let [sum (+ n1 n2)]]}
{:nums [n1 n2] :sum sum})
与 {{gen/tuple}} 相比,这个方法的优势在于将生成器在语法上放置在名称旁边,而不是将生成器与名称隔离。