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

欢迎!请在关于页面查看更多关于这是如何工作的信息。

+1
Spec
下面的示例展示了在一个已规范的表单中,在反规范后没有进一步的规范。我期望您可以重复进行conform -> unform -> conform,并得到相同的结果。


(require '[clojure.core.specs])
(require '[clojure.spec :as s])

(s/def ::defn-macro (s/cat :type #{'defn} :definition :clojure.core.specs/defn-args))

(let [form '(defn foo "bar" ([a & b] a a c) ([a b] a))]

  (-> form
       (->> (s/conform ::defn-macro))) ;;=> {:type defn, :definition {:name foo, :docstring "bar", :bs [:arity-n {:bodies [{:args {:args [[:sym a]], :varargs {:amp &, :form [:sym b]}}, :body [a a c]} {:args {:args [[:sym a] [:sym b]]}, :body [a]}]}]}}

  ;; 反规范返回了函数定义,但参数以列表形式而不是向量形式
  (->> form
       (s/conform ::defn-macro)
       (s/unform ::defn-macro))  ;;=> (defn foo "bar" ((a (& b)) a a c) ((a b) a)))

  ;; 反规范后再进行规范不再可行
  (->> form
       (s/conform ::defn-macro)
       (s/unform ::defn-macro)
       (s/conform ::defn-macro)) ;;=> :clojure.spec/invalid

    )

7 答案

+1

对于“正则表达式集合也必须是向量”的特定案例,使用spec 1来实现这一点并不是真正可能的,使其对所有conform、unform和gen都起作用。

在spec 2中,我们添加了对非流动s/and的支持(目前称为s/and-,但这名字仍在变动,可能最终会变成s/union或其他),这是添加需要将集合强制为向量或序列的s/cat变体(如s/catv和s/cats)所必需的。

最终,我们将使用spec2重写core.specs,并使用s/catv来定义defn参数向量,这将解决这个问题。

0

由 jeroen 发布的评论

此段落展示了以上代码的更好格式:https://gist.github.com/jeroenvandijk/28c6cdd867dbc9889565dca92673a531

0

由 lgs32a 发布的评论

这个问题可以迅速追溯到 :clojure.core.specs/arg-list,该部分被指定为 (s/and vector?)。在不进行统一格式化时,它不会创建一个向量。

考虑一下,vcat 在这种和类似的案例中会很好用。

0

由 marco.m 发布的评论

你好,有什么新消息吗?

0

由 alexmiller 发布的评论

没有。

0

由 jeroen 发布的评论

又发现了另一个问题

(->> '(foo (link: h0 & [h1]))
(s/conform :clojure.core.specs.alpha/defn-args)
(s/unform :clojure.core.specs.alpha/defn-args))
;#=> '(foo (link: h0 (& [h1))))

这里剩余的参数被包裹在一个额外的列表中。我应该在哪里报告这个问题?

0
参考: https://clojure.atlassian.net/browse/CLJ-2021 (由 jeroen 报告)
...