clojure - 为具有跨层约束的嵌套数据结构创建 Clojure 规范生成器

标签 clojure clojure.spec

我正在使用 Clojure 规范来规范一个简单的数据结构:

{:max 10
 :data [[3 8 1]
        [9 0 1]]}

:data 值是由从零到 :max 值(含)区间内的整数组成的等大小向量组成的向量。我用规范表达了这一点,如下:

(s/def ::max pos-int?)
(s/def ::row (s/coll-of nat-int? :kind vector?, :min-count 1))
(s/def ::data (s/and (s/coll-of ::row :kind vector?, :min-count 1)
                     #(apply = (map count %))))

(s/def ::image (s/and (s/keys :req-un [::max ::data])
                      (fn [{:keys [max data]}]
                        (every? #(<= 0 % max) (flatten data)))))

自动生成器适用于前三个规范,但不适用于 ::image(s/exercise::image) 尝试 100 次后总是失败。

我尝试为 ::image 创建自定义生成器,但没有成功。我不知道如何表达跨越嵌套结构层的约束(键 :max 约束其他地方的向量中的值)。

是否可以创建一个生成 ::image 的 Clojure spec/test.check 生成器?

最佳答案

当然!这里的关键是创建域模型。这里我认为模型是max、col-size、row-size。这足以生成一个有效的示例。

所以像这样:

(def image-gen
  (gen/bind
    (s/gen (s/tuple pos-int? (s/int-in 1 8) (s/int-in 1 8)))
    (fn [[max rows cols]]
      (gen/hash-map
        :max (s/gen #{max})
        :data (gen/fmap #(into [] (partition-all cols) %)
                (s/gen (s/coll-of (s/int-in 0 (inc max)) 
                                  :kind vector?
                                  :count (* rows cols))))))))

首先,我们生成一个 [<max-value> <rows> <cols>] 的元组。 gen/bind然后返回一个新的生成器,该生成器创建所需形状的 map 。我们嵌套gen/fmap在里面构建所有随机数据值的向量,然后将其重新整形为正确的嵌套向量形式。

然后您可以将其合并到图像中:

(s/def ::image
  (s/with-gen 
    (s/and (s/keys :req-un [::max ::data])
           (fn [{:keys [max data]}]
             (every? #(<= 0 % max) (flatten data))))
    (fn [] image-gen)))

需要注意的一件可能有趣的事情是,我将行和列限制为不超过 7,因为生成器可能会尝试生成非常大的随机随机样本值。需要绑定(bind)这样的东西在自定义生成器中很常见。

通过付出更多努力,您还可以更好地重用其中一些规范和生成器部件。

关于clojure - 为具有跨层约束的嵌套数据结构创建 Clojure 规范生成器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43920066/

相关文章:

clojure - 关闭 repl 中的 *print-namespace-maps*

vector - Clojure 从指定位置的 Vector 中删除项目

clojure - 从 Compojure 提供静态文件

java - 为什么这两种素数采样方法运行的时间一样长?

clojure - :pre & :post defn conditions become obsolete after core.规范是否被引入?

Clojure.spec - 为什么有用以及何时使用

clojure - 将 Cider 连接到 Luminus +CLJS Figwheel repl

clojure 规范 - 验证 map 的内容

clojure - 使用 clojure.spec 解析