为什么 Clojure Spec 会在这里进入无限循环?
Why is Clojure Spec going into an infinite loop here?
这是一个将视觉模式表示为 S 形集合的应用程序。
一个Sshape(有样式的形状)是一个点列表和一个样式信息图。
一个 APattern 是一个包含 Sshape 列表的记录。
这是规范:
在sshape.clj
(spec/def ::stroke-weight int?)
(spec/def ::color (spec/* int?))
(spec/def ::stroke ::color)
(spec/def ::fill ::color)
(spec/def ::hidden boolean?)
(spec/def ::bezier boolean?)
(spec/def ::style (spec/keys :opt-un [::stroke-weight ::stroke ::fill ::hidden ::bezier]))
(spec/def ::point (spec/* number?))
(spec/def ::points (spec/* ::point))
(spec/def ::SShape (spec/keys :req-un [::style ::points]))
在groups.clj
(spec/def ::sshapes (spec/* :patterning.sshapes/SShape))
(spec/def ::APattern (spec/keys :req-un [::sshapes]))
然后在另一个文件中,我尝试测试将两个 APatterns 放在一起的叠加函数是否接受 APatterns
(defn superimpose-layout "simplest layout, two patterns located on top of each other "
[pat1 pat2]
{:pre [(spec/valid? :patterning.groups/APattern pat1)]}
(->APattern (concat (:sshapes pat1) (:sshapes pat2))) )
在没有前提条件的情况下运行。
有了前提条件,我得到了这个无限递归和堆栈溢出。
Exception in thread "main" java.lang.WhosebugError, compiling:(/tmp/form-init7774655152686087762.clj:1:73)
at clojure.lang.Compiler.load(Compiler.java:7526)
at clojure.lang.Compiler.loadFile(Compiler.java:7452)
at clojure.main$load_script.invokeStatic(main.clj:278)
at clojure.main$init_opt.invokeStatic(main.clj:280)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invokeStatic(main.clj:311)
at clojure.main$null_opt.invokeStatic(main.clj:345)
at clojure.main$null_opt.invoke(main.clj:342)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)
Caused by: java.lang.WhosebugError
at clojure.spec.alpha$regex_QMARK_.invokeStatic(alpha.clj:81)
at clojure.spec.alpha$regex_QMARK_.invoke(alpha.clj:78)
at clojure.spec.alpha$maybe_spec.invokeStatic(alpha.clj:108)
at clojure.spec.alpha$maybe_spec.invoke(alpha.clj:103)
at clojure.spec.alpha$the_spec.invokeStatic(alpha.clj:117)
at clojure.spec.alpha$the_spec.invoke(alpha.clj:114)
at clojure.spec.alpha$dt.invokeStatic(alpha.clj:742)
at clojure.spec.alpha$dt.invoke(alpha.clj:738)
at clojure.spec.alpha$dt.invokeStatic(alpha.clj:739)
at clojure.spec.alpha$dt.invoke(alpha.clj:738)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1480)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1491)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1491)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
等等
更新:
好的。我在回复中缩小了范围。
假设定义了一个点向量,使得 pts
是
[[-0.3 -3.6739403974420595E-17] [1.3113417037298127E-8 -0.2999999999999997] [0.2999999999999989 2.6226834037856828E-8] [-3.934025103841547E-8 0.29999999999999744] [-0.3 -3.6739403974420595E-17]]
然后调用
(spec/valid? :patterning.sshapes/points pts)
给我堆栈溢出:
WhosebugError clojure.spec.alpha/regex? (alpha.clj:81)
所以它看起来只是因为我正在尝试匹配 spec/* 的 spec/* 数字。
嵌套向量触发这种无限递归是否有某种原因?
我相信 Clojure 规范在这方面存在一些错误。
这个看起来像 https://dev.clojure.org/jira/browse/CLJ-2002 的实例。它在符合时触发:
(s/conform (s/* (s/* number?)) [[]]) ; => WhosebugError
为此,您可能应该使用 spec/coll-of
而不是 s/*
:
(s/def ::point (s/coll-of number?))
(s/def ::points (s/coll-of ::point))
(s/def ::SShape (s/keys :req-un [::style ::points]))
(s/exercise (s/coll-of ::SShape))
;; => ([[] []] [[{:style {:hidden false, :bezier false}, :points [[1.0 -3.0 0 0.75 -1.0 -1.0 0 -1.5 1.0 3.0 -1 0] [-2.0 -1 2.0 2.0 0 ...
这是一个将视觉模式表示为 S 形集合的应用程序。
一个Sshape(有样式的形状)是一个点列表和一个样式信息图。
一个 APattern 是一个包含 Sshape 列表的记录。
这是规范:
在sshape.clj
(spec/def ::stroke-weight int?)
(spec/def ::color (spec/* int?))
(spec/def ::stroke ::color)
(spec/def ::fill ::color)
(spec/def ::hidden boolean?)
(spec/def ::bezier boolean?)
(spec/def ::style (spec/keys :opt-un [::stroke-weight ::stroke ::fill ::hidden ::bezier]))
(spec/def ::point (spec/* number?))
(spec/def ::points (spec/* ::point))
(spec/def ::SShape (spec/keys :req-un [::style ::points]))
在groups.clj
(spec/def ::sshapes (spec/* :patterning.sshapes/SShape))
(spec/def ::APattern (spec/keys :req-un [::sshapes]))
然后在另一个文件中,我尝试测试将两个 APatterns 放在一起的叠加函数是否接受 APatterns
(defn superimpose-layout "simplest layout, two patterns located on top of each other "
[pat1 pat2]
{:pre [(spec/valid? :patterning.groups/APattern pat1)]}
(->APattern (concat (:sshapes pat1) (:sshapes pat2))) )
在没有前提条件的情况下运行。
有了前提条件,我得到了这个无限递归和堆栈溢出。
Exception in thread "main" java.lang.WhosebugError, compiling:(/tmp/form-init7774655152686087762.clj:1:73)
at clojure.lang.Compiler.load(Compiler.java:7526)
at clojure.lang.Compiler.loadFile(Compiler.java:7452)
at clojure.main$load_script.invokeStatic(main.clj:278)
at clojure.main$init_opt.invokeStatic(main.clj:280)
at clojure.main$init_opt.invoke(main.clj:280)
at clojure.main$initialize.invokeStatic(main.clj:311)
at clojure.main$null_opt.invokeStatic(main.clj:345)
at clojure.main$null_opt.invoke(main.clj:342)
at clojure.main$main.invokeStatic(main.clj:424)
at clojure.main$main.doInvoke(main.clj:387)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:702)
at clojure.main.main(main.java:37)
Caused by: java.lang.WhosebugError
at clojure.spec.alpha$regex_QMARK_.invokeStatic(alpha.clj:81)
at clojure.spec.alpha$regex_QMARK_.invoke(alpha.clj:78)
at clojure.spec.alpha$maybe_spec.invokeStatic(alpha.clj:108)
at clojure.spec.alpha$maybe_spec.invoke(alpha.clj:103)
at clojure.spec.alpha$the_spec.invokeStatic(alpha.clj:117)
at clojure.spec.alpha$the_spec.invoke(alpha.clj:114)
at clojure.spec.alpha$dt.invokeStatic(alpha.clj:742)
at clojure.spec.alpha$dt.invoke(alpha.clj:738)
at clojure.spec.alpha$dt.invokeStatic(alpha.clj:739)
at clojure.spec.alpha$dt.invoke(alpha.clj:738)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1480)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1491)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1491)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
at clojure.spec.alpha$deriv.invoke(alpha.clj:1474)
at clojure.spec.alpha$deriv.invokeStatic(alpha.clj:1492)
等等
更新:
好的。我在回复中缩小了范围。
假设定义了一个点向量,使得 pts
是
[[-0.3 -3.6739403974420595E-17] [1.3113417037298127E-8 -0.2999999999999997] [0.2999999999999989 2.6226834037856828E-8] [-3.934025103841547E-8 0.29999999999999744] [-0.3 -3.6739403974420595E-17]]
然后调用
(spec/valid? :patterning.sshapes/points pts)
给我堆栈溢出:
WhosebugError clojure.spec.alpha/regex? (alpha.clj:81)
所以它看起来只是因为我正在尝试匹配 spec/* 的 spec/* 数字。
嵌套向量触发这种无限递归是否有某种原因?
我相信 Clojure 规范在这方面存在一些错误。
这个看起来像 https://dev.clojure.org/jira/browse/CLJ-2002 的实例。它在符合时触发:
(s/conform (s/* (s/* number?)) [[]]) ; => WhosebugError
为此,您可能应该使用 spec/coll-of
而不是 s/*
:
(s/def ::point (s/coll-of number?))
(s/def ::points (s/coll-of ::point))
(s/def ::SShape (s/keys :req-un [::style ::points]))
(s/exercise (s/coll-of ::SShape))
;; => ([[] []] [[{:style {:hidden false, :bezier false}, :points [[1.0 -3.0 0 0.75 -1.0 -1.0 0 -1.5 1.0 3.0 -1 0] [-2.0 -1 2.0 2.0 0 ...