隨着Spec的推出,我嘗試爲我的所有函數編寫test.check生成器。這對簡單的數據結構來說很好,但對於具有相互依賴的部分的數據結構往往會變得困難。換句話說,發電機內的一些國家管理部門是需要的。test.check中的循環和狀態管理
Clojure循環的生成器等價物/遞歸或減少已經非常有幫助,因此一次迭代中生成的值可以存儲在某個聚合值中,然後在隨後的迭代中可以訪問該聚合值。
一個簡單的例子,其中,這將是必需的,是提供一種用於拆分集合的發生器寫入準確X分區,零和Y的元素,並且其中所述元件然後隨機分配到任何之間具有每個分區的分區。 (請注意,
test.chuck
的partition
函數不允許指定X或Y)。如果你寫這個發電機通過收集循環,那麼這將需要訪問以前的迭代過程中填補了分區,以避免超過Y.
沒有任何人有什麼想法?部分的解決方案,我發現:
- test.check的
let
和bind
允許您以後在生成一個值,然後重新使用該值,但他們不允許重複。 您可以使用
tuple
和bind
函數的組合迭代以前生成的值的集合,但是這些迭代無法訪問先前迭代期間生成的值。(defn bind-each [k coll] (apply tcg/tuple (map (fn [x] (tcg/bind (tcg/return x) k)) coll))
可以使用原子(或揮發物)來存儲先前迭代期間產生&訪問值。這是有效的,但是非常不合適,特別是因爲在生成器返回之前你需要原子/易失性
reset!
,以避免它們的內容在下一次生成器調用時被重用。由於它們的
bind
和return
函數,發生器具有類似monad的功能,這暗示了使用monad庫(如Cats)與狀態monad結合使用。然而,在Cats 2.0中刪除了State monad(因爲據說它不適合Clojure),而我知道的其他支持庫沒有正式的Clojurescript支持。此外,在他自己的圖書館中實施國家monad時,Clojure的monad專家之一Jim Duey似乎警告說,使用State monad與test.check的收縮不兼容(參見http://www.clojure.net/2015/09/11/Extending-Generative-Testing/的底部),這會顯着降低使用test.check的優點。
謝謝! (我現在想知道爲什麼遞歸的想法不是自然而然地發生在我身上......)你能否擴展你的「破壞縮小的過程」?在我的(當然還是有限的)測試中,包含許多讓/綁定的生成器,我似乎對發生的收縮感到高興。你是否知道任何更可能破壞收縮的具體情況? –
這裏描述的問題:http://dev.clojure.org/jira/browse/TCHECK-112 – gfredericks
我還應該澄清,如果你有多個子句,'gen/let'只會導致一個真正的'gen/bind'或者如果身體本身就是發電機。否則它等同於'gen/fmap'。 – gfredericks