使用Clojure Spec从递归定义生成 [英] Generating from recursive definitions with Clojure Spec
问题描述
让我们考虑打Clo语法的Clojure Spec正则表达式
Let's consider a Clojure Spec regexp for hiccup syntax
(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..."]]}]]}
直到您尝试根据规范为函数生成一些示例数据
until you try to generate some example data for your functions from the spec
(require '[clojure.spec.gen :as gen])
(gen/generate (spec/gen ::hiccup))
; No return value but:
; 1. Unhandled java.lang.OutOfMemoryError
; GC overhead limit exceeded
是否可以重写规范以使其生成有效的生成器?还是我们必须在规范中附加一些简化的生成器?
Is there a way to rewrite the spec so that it produces a working generator? Or do we have to attach some simplified generator to the spec?
推荐答案
spec / *的意图recursion-limit *
(默认值为4)是为了限制递归生成,使其可以正常工作。因此,要么在某些规范提示( *
或或
)之一中无法正常工作,要么您看到了快速增长在其他内容中(例如 map?
或字符串)。不做任何修改,很难知道是什么问题。
The intent of spec/*recursion-limit*
(default 4) is to limit recursive generation such that this should work. So either that's not working properly in one of the spec impls (*
or or
), or you are seeing rapid growth in something else (like map?
or the strings). Without doing some tinkering, it's hard to know which is the problem.
这确实为我产生了(一个非常大的例子):
This does generate (a very large example) for me:
(binding [spec/*recursion-limit* 1] (gen/generate (spec/gen ::hiccup)))
我确实看到了几个基数很大的区域,即使在一个例子中- *
和生成的属性 map的大小?
。两者都可能受到进一步限制。将这些部分进一步细分为更细粒度的规范,并在必要时提供覆盖生成器将是最容易的(属性映射只能使用 map-of
和:gen-max
)。
I do see several areas where the cardinalities are large even in that one example - the *
and the size of the generated attributes map?
. Both of those could be further constrained. It would be easiest to break these parts up further into more fine-grained specs and supply override generators where necessary (the attribute map could just be handled with map-of
and :gen-max
).
这篇关于使用Clojure Spec从递归定义生成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!