3

Spec の導入により、すべての関数に対して test.check ジェネレーターを作成しようとしています。これは単純なデータ構造では問題ありませんが、相互に依存する部分を持つデータ構造では困難になる傾向があります。つまり、ジェネレーター内で何らかの状態管理が必要になります。

Clojure の loop/recur または reduce に相当するジェネレーターを用意することは、すでに非常に役立ちます。これにより、1 つの反復で生成された値を、後続の反復でアクセスできる集計値に格納できます。

これが必要となる簡単な例の 1 つは、コレクションを正確に X 個のパーティションに分割するジェネレータを作成することです。各パーティションは 0 から Y 個の要素を持ち、要素は任意のパーティションにランダムに割り当てられます。test.chuck(のpartition関数では、X または Y を指定できないことに注意してください)。

コレクションをループしてこのジェネレーターを作成する場合、Y を超えないようにするために、前の反復中にいっぱいになったパーティションにアクセスする必要があります。

誰にもアイデアはありますか?私が見つけた部分的な解決策:

  • test.checkletbind使用すると、値を生成して後でその値を再利用できますが、反復は許可されません。

  • tupleと関数を組み合わせて、以前に生成された値のコレクションを反復処理できますbindが、これらの反復では、以前の反復中に生成された値にアクセスできません。

    (defn bind-each [k coll] (apply tcg/tuple (map (fn [x] (tcg/bind (tcg/return x) k)) coll))

  • アトム (または揮発性) を使用して、前の反復中に生成された値を保存およびアクセスできます。reset!これは機能しますが、特に、ジェネレーターが返される前にアトム/揮発性が必要なため、ジェネレーターの次の呼び出しでそれらの内容が再利用されるのを避けるために、Clojure とはまったく異なります。

  • bindジェネレーターは、そのand関数によりモナドに似てreturnいます。これは、Cats などのモナド ライブラリーを State モナドと組み合わせて使用​​することを示唆しています。ただし、State モナドは Cats 2.0 で削除されました (Clojure に適していないと言われているため)。一方、私が知っている他のサポート ライブラリでは、Clojurescript が正式にサポートされていません。さらに、Clojure のモナド専門家の 1 人である Jim Duey は、自身のライブラリに State モナドを実装する際に、State モナドの使用は test.check の縮小と互換性がないと警告しているようです ( http://www.これは、 test.checkを使用するメリットを大幅に減らします。

4

1 に答える 1

2

明示的な再帰と組み合わせてgen/let(または同等に)、説明している反復を実現できます。gen/bind

(defn make-foo-generator
  [state]
  (if (good-enough? state)
    (gen/return state)
    (gen/let [state' (gen-next-step state)]
      (make-foo-generator state'))))

ただしlet、 /を使用するたびbindに縮小プロセスが損なわれるため、可能であればこのパターンを回避することをお勧めします。を使用してジェネレーターを再編成できる場合がありgen/fmapます。たとえば、コレクションを X サブセットのシーケンスに分割するには (これはあなたの例とまったく同じではありませんが、調整して調整できると思います)、次のようにすることができます。

(defn partition
  [coll subset-count]
  (gen/let [idxs (gen/vector (gen/choose 0 (dec subset-count))
                             (count coll))]
    (->> (map vector coll idxs)
         (group-by second)
         (sort-by key)
         (map (fn [[_ pairs]] (map first pairs))))))
于 2016-10-31T13:45:24.277 に答える