代码之家  ›  专栏  ›  技术社区  ›  ericky

clojure spec和“在100次尝试之后无法满足这样的谓词…”

  •  1
  • ericky  · 技术社区  · 6 年前

    假设你有一个 ::givee 以及 ::giver :

    (s/def ::givee keyword?)
    (s/def ::giver keyword?)
    

    形成一个 unq/gift-pair 以下内容:

    (s/def :unq/gift-pair (s/keys :req-un [::givee ::giver]))
    

    然后你有一个 :unq/gift-history 这是一个 vector 属于 UNQ/礼品对 以下内容:

    (s/def :unq/gift-history (s/coll-of :unq/gift-pair :kind vector?))
    

    最后,假设您要替换 :unq/gift-pair 矢量 :

    (defn set-gift-pair-in-gift-history [g-hist g-year g-pair]
      (assoc g-hist g-year g-pair))
    (s/fdef set-gift-pair-in-gift-history
            :args (s/and (s/cat :g-hist :unq/gift-history
                                :g-year int?
                                :g-pair :unq/gift-pair)
                         #(< (:g-year %) (count (:g-hist %)))
                         #(> (:g-year %) -1))
            :ret :unq/gift-history)
    

    一切正常:

    (s/conform :unq/gift-history
               (set-gift-pair-in-gift-history [{:givee :me, :giver :you} {:givee :him, :giver :her}] 1 {:givee :dog, :giver :cat}))
    => [{:givee :me, :giver :you} {:givee :dog, :giver :cat}]
    

    直到我试着 stest/check 它:

    (stest/check `set-gift-pair-in-gift-history)
                 clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries.
    java.util.concurrent.ExecutionException: clojure.lang.ExceptionInfo: Couldn't satisfy such-that predicate after 100 tries. {}
    

    我试过用 s/int-in 限制向量计数(认为这可能是问题所在)而没有成功。

    有什么关于跑步的想法吗 (stest/check `set-gift-pair-in-gift-history) 正确地?

    谢谢您。

    1 回复  |  直到 6 年前
        1
  •  2
  •   Taylor Wood    6 年前

    问题是向量的生成器和集合中的索引是独立的/不相关的。随机向量和整数不满足以下条件:

    #(< (:g-year %) (count (:g-hist %)))
    #(> (:g-year %) -1)
    

    check 这个函数可以提供一个自定义生成器来生成 :unq/gift-history 向量,并基于该向量的大小为索引构建另一个生成器:

    (s/fdef set-gift-pair-in-gift-history
      :args (s/with-gen
              (s/and
                (s/cat :g-hist :unq/gift-history
                       :g-year int?
                       :g-pair :unq/gift-pair)
                #(< (:g-year %) (count (:g-hist %)))
                #(> (:g-year %) -1))
              #(gen/let [hist (s/gen :unq/gift-history)
                         year (gen/large-integer* {:min 0 :max (max 0 (dec (count hist)))})
                         pair (s/gen :unq/gift-pair)]
                 [hist year pair]))
      :ret :unq/gift-history)
    

    这是使用测试。检查 let 宏,这是 bind / fmap 它允许您使用类似于 是的。自定义生成器将参数向量返回给函数。