繁体   English   中英

Clojure规范的哈希图具有相互依赖的值?

[英]clojure spec for hash-map with interdependent values?

我想为哈希映射写一个clojure规范,其中一个键的值被约束为等于其他两个键的值之和。 我知道一种为这种规范手工编写测试生成器的方法:

(ns my-domain)
(require '[clojure.test           :refer :all     ]
         '[clojure.spec.alpha     :as s           ]
         '[clojure.spec.gen.alpha :as gen         ]
         '[clojure.pprint         :refer (pprint) ])

(s/def ::station-id string?)
(s/def ::sim-time (s/double-in :infinite? true, :NaN? false))
(s/def ::reserved-counts (s/and int? #(not (neg? %))))
(s/def ::free-counts     (s/and int? #(not (neg? %))))

(def counts-preimage (s/gen (s/keys :req [::station-id
                                          ::sim-time
                                          ::reserved-counts
                                          ::free-counts])))

(pprint (gen/generate
         (gen/bind
          counts-preimage
          #(gen/return
            (into % {::total-counts
                     (+ (::reserved-counts %)
                        (::free-counts %))})))))
 #:my-domain{:station-id "sHN8Ce0tKWSdXmRd4e46fB", :sim-time -3.4619293212890625, :reserved-counts 58, :free-counts 194, :total-counts 252} 

但是我还没有弄清楚如何编写规范,更不用说产生类似生成器的规范了。 问题的要点在于,在规范的范围内,我缺乏一种掌握规范中“原像”的方法,也就是说,我缺乏从生成器空间bind的类似物。 这是一次失败的尝试:

(s/def ::counts-partial-hash-map
  (s/keys :req [::station-id
                ::sim-time
                ::reserved-counts
                ::free-counts]))
(s/def ::counts-attempted-hash-map
  (s/and ::counts-partial-hash-map
         #(into % {::total-counts (+ (::reserved-counts %)
                                     (::free-counts %))})))

(pprint (gen/generate (s/gen ::counts-attempted-hash-map)))
 #:my-domain{:station-id "ls5qBUoF", :sim-time ##Inf, :reserved-counts 56797960, :free-counts 17} 

生成的样本符合规范,因为#(into % {...})是真实的,但是结果不包含键为::total-counts的新属性。

如有任何指导,我将不胜感激。

编辑 :今天我了解了s/with-gen ,这将使我可以将(工作的)测试生成器附加到我的“原像”或“部分”规范中。 也许那是最好的前进方向?

您可以使用nat-int? 谓词(有一个内置的规范,感谢@glts)作为计数键,并且还添加了::total-counts规范:

(s/def ::reserved-counts nat-int?)
(s/def ::free-counts nat-int?)
(s/def ::total-counts nat-int?)

(s/def ::counts-partial-hash-map
  (s/keys :req [::station-id
                ::sim-time
                ::reserved-counts
                ::free-counts]))

哈希映射的规范,其中键之一的值被约束为等于其他两个键的值之和

要添加这种说法,您可以s/and与谓语功能keys规范(或本例中的merge规范是合并了部分地图规范::total-count键SPEC):

(s/def ::counts-attempted-hash-map
  (s/with-gen
    ;; keys spec + sum-check predicate
    (s/and
      (s/merge ::counts-partial-hash-map (s/keys :req [::total-counts]))
      #(= (::total-counts %) (+ (::reserved-counts %) (::free-counts %))))
    ;; custom generator
    #(gen/fmap
       (fn [m]
         (assoc m ::total-counts (+ (::reserved-counts m) (::free-counts m))))
       (s/gen ::counts-partial-hash-map))))

它还使用with-gen将自定义生成器与将::total-count设置为其他count键之和的规范相关联。

(gen/sample (s/gen ::counts-attempted-hash-map) 1)
=> (#:user{:station-id "", :sim-time 0.5, :reserved-counts 1, :free-counts 1, :total-counts 2})

生成的样本符合规范,因为#(into % {...})是真实的,但是结果不包含键为::total-counts的新属性。

我建议不要使用规格来计算::total-counts到地图中。 规范通常不应该用于数据转换。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM