5

让我们考虑一个用于打嗝语法的 Clojure Spec 正则表达式

(require '[clojure.spec :as spec])

(spec/def ::hiccup
  (spec/cat :tag        keyword?
            :attributes (spec/? map?)
            :content    (spec/* (spec/or :terminal string?
                                         :element  ::hiccup))))

效果很好

(spec/conform ::hiccup [:div#app [:h5 {:id "loading-message"} "Connecting..."]])
; => {:tag :div#app, :content [[:element {:tag :h5, :attributes {:id "loading-message"}, :content [[:terminal "Connecting..."]]}]]}

直到您尝试从规范中为您的函数生成一些示例数据

(require '[clojure.spec.gen :as gen])
(gen/generate (spec/gen ::hiccup))
; No return value but:
; 1. Unhandled java.lang.OutOfMemoryError
;    GC overhead limit exceeded

有没有办法重写规范,以便它产生一个工作生成器?还是我们必须在规范中附加一些简化的生成器?

4

1 回答 1

3

(默认 4)的目的spec/*recursion-limit*是限制递归生成,以便它应该工作。*因此,要么在规范实现(或)之一中无法正常工作or,要么您看到其他事物(如map?字符串)的快速增长。如果不做一些修补,很难知道哪个是问题所在。

这确实为我生成(一个非常大的例子):

(binding [spec/*recursion-limit* 1] (gen/generate (spec/gen ::hiccup)))

即使在那个示例中,我也确实看到了基数很大的几个领域 -*生成属性的大小和大小map?。这两者都可能受到进一步限制。将这些部分进一步分解为更细粒度的规范并在必要时提供覆盖生成器是最简单的(属性映射可以只用map-ofand处理:gen-max)。

于 2017-04-21T16:22:58.030 回答