2024 Clojure 状态调查!中分享您的想法。

欢迎!请查看关于页面,了解有关其如何工作的更多信息。

0投票
Spec

(另请参阅已关闭的 http://dev.clojure.org/jira/browse/CLJ-1964

(require '[clojure.spec :as s]) (s/def ::map-tree (s/map-of keyword? (s/or :tree ::map-tree :leaf nil?))) (s/exercise ::map-tree)

在我的机器上停滞。

以下是从https://groups.google.com/forum/#!topic/clojure/IvKJc8dEhts提供的另一个示例,这立即导致在我的机器上产生 StackOverflowError

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

(defrecord Tree [name children])
(defrecord Leaf [name])

(s/def ::name string?)
(s/def ::children (s/coll-of (s/or :tree ::Tree, :leaf ::Leaf)))

(s/def ::Leaf (s/with-gen

            (s/keys :req-un [::name])
            #(gen/fmap (fn [name] (->Leaf name)) (s/gen ::name))))

(s/def ::Tree (s/with-gen

            (s/keys :req-un [::name ::children])
            #(gen/fmap
               (fn [[name children]] (->Tree name children))
               (s/gen (s/tuple ::name ::children)))))

偶尔生成,但通常导致 StackOverflow
(binding [s/*recursion-limit* 1]

(gen/generate (s/gen ::Tree)))

StackOverflowError

clojure.lang.RT.seqFrom (RT.java:533)
clojure.lang.RT.seq (RT.java:527)
clojure.core/seq--6221 (core.clj:137)
clojure.core/map/fn--6687 (core.clj:2736)
clojure.lang.LazySeq.sval (LazySeq.java:40)
clojure.lang.LazySeq.seq (LazySeq.java:49)
clojure.lang.RT.seq (RT.java:525)
clojure.core/seq--6221 (core.clj:137)
clojure.core/every? (core.clj:2652)
clojure.spec/tuple-impl/reify--13509 (spec.clj:905)
clojure.spec/gensub (spec.clj:228)
clojure.spec/gen (spec.clj:234)

`

5 个答案

0投票

评论来自:lgs32a

作为 CLJ-1964 的作者,我无法确认这一点。

(binding [s/*recursion-limit* 1] (s/exercise ::map-tree))

... 立即生成。

使用新的 :gen-max 参数规范也可以在合理的时间内以更高的递归限制生成

`
(s/def ::map-tree (s/map-of keyword? (s/or :tree ::map-tree :leaf nil?)

                        :gen-max 3))

(time (s/exercise ::map-tree))
"执行时间:0.135683 毫秒"
`

注意::gen-max 默认为 20,所以有 4 次递归步骤,这将迅速生成 20^5 即 320万 个值

0投票

评论来自:alexmiller

我今天再次尝试,第一个例子仍然可以正常工作。我正在使用 Java 1.8 并在基本的 Clojure repl 中使用默认设置(不是 lein)。

0投票

评论者:mtruyens

使用`:gen-max`选项后,现在一切正常。感谢您的建议!

0投票

评论者:kenran

第一个例子对我来说也运行正常,但我有一个与第二个类似的问题。除非我将`:gen-max`或`:max-count`设置为低值(例如2),否则以下代码会很快出现栈溢出。

`
(require '[clojure.spec.alpha :as s])
(require '[clojure.spec.gen.alpha :as gen])

(s/def ::bar string?)
(s/def ::baz (s/coll-of (s/or :s string? :b ::foo)))
(s/def ::foo
(s/spec
map?
:gen
#(s/gen

 (s/keys :req [::bar ::baz]))))

(gen/generate (s/gen ::foo))
`

The s/spec (或者 s/with-gen,我也试过)看起来是这里的问题,因为下面的代码运行良好并应该生成等效的数据

`
(s/def ::bar2 string?)
(s/def ::baz2 (s/coll-of (s/or :s2 string? :b2 ::foo2)))
(s/def ::foo2 (s/keys :req [::bar2 ::baz2]))

(gen/generate (s/gen ::foo2))
`

我使用的是java 10.0.2 64位,但我的一位同事可以用最新的java 8重现这个问题。

我是不是用错了,还是哪里隐藏着问题?

0投票
参考:[https://clojure.atlassian.net/browse/CLJ-1978](https://clojure.atlassian.net/browse/CLJ-1978)(由alex+import报告)
...