Clojure规范-与规范/一起发布或嵌套在规范/和中

Clojure规范-与规范/一起发布或嵌套在规范/和中,clojure,clojure.spec,Clojure,Clojure.spec,我最近在试用Clojure规范,遇到了一条意外的错误消息。我发现,如果你有一个等级库/或嵌套在等级库/中,然后等级库函数在等级库/或分支之后,会传递一个一致的值,而不是顶级值 您可以在此处“v”的打印值中看到这一点(人为示例): 我认为这可能是spec/and的文档字符串故意造成的: 采用谓词/规范形式,例如 (s/甚至?#(

我最近在试用Clojure规范,遇到了一条意外的错误消息。我发现,如果你有一个等级库/或嵌套在等级库/中,然后等级库函数在等级库/或分支之后,会传递一个一致的值,而不是顶级值

您可以在此处“v”的打印值中看到这一点(人为示例):

我认为这可能是spec/and的文档字符串故意造成的:

采用谓词/规范形式,例如

(s/甚至?#(<%42))

返回返回符合条件的值的规范<强>连续 一致的值通过其余谓词传播。

但这对我来说似乎有悖常理,因为这会妨碍规范谓词的重用,因为它们需要编写为接受“[]”

如果有多个等级库/或分支,情况会变得更糟:

(spec/valid? (spec/and (spec/or :always-true (constantly true))
                       (spec/or :also-always-true (constantly true))
                       (fn [v]
                         (println "v:" v)
                       (constantly true)))
         nil)
v: [:also-always-true [:always-true nil]]
=> true
我错过了一些基本的东西吗

但这似乎与我的直觉背道而驰,因为它会妨碍规范谓词的重用

在国际海事组织,这些行为的替代方案吸引力较小:

  • 默认情况下,放弃
    s/或
    的一致标记。如果我们愿意,我们可以随时丢弃它,但我们不希望clojure.spec为我们做出这样的决定。Spec假设我们想知道哪个
    s/或
    分支匹配
  • 不要在
    s/和
    中流动一致的值,以牺牲规范/谓词的可组合性为代价
幸运的是,如果需要,我们可以丢弃
s/或
标记。这里有两个选项:

  • s/或
    包装在
    s/nonforming
    中。感谢glts在下面的评论提醒我这个(未记录的)功能

    (s/valid?
      (s/and
        (s/nonconforming (s/or :s string? :v vector?))
        empty?)
      "")
    => true
    
  • s/和
    s/或
    规范带有一个丢弃标签的
    s/符合者

    (s/valid?
      (s/and
        (s/and (s/or :s string? :v vector?)
               ;; discard `s/or` tag here
               (s/conformer second))
        empty?)
      [])
    => true
    
    如果经常需要,可以使用宏简化样板文件:

    (defmacro dkdc-or [& key-pred-forms]
      `(s/and (s/or ~@key-pred-forms) (s/conformer second)))
    
如果有多个等级库/分支,情况会变得更糟


如果您正在为允许备选方案的数据编写规范(例如,
s/或
s/alt
),并且您正在将有效的备选方案“流动”到后续谓词(
s/和
),在我看来,在后续谓词中掌握这些知识通常更有用。我很想看到这种规格更现实的用例,因为可能有更好的方式来规格说明。

您也可以使用
s/unconcentrative
而不是conformer。Taylor很高兴阅读您的答案,总是用一个基本原理来回答真正的问题,而不是那些可能解决问题但无助于理解的快速而肮脏的代码。谢谢谢谢你花时间写了一个很好的答案。我理解你们的观点,但最终我可以看到这会让很多人绊倒,他们从小处做起,用简单的谓词建立规范,然后,正如我发现的,当你们试图将它们和and/or操作结合起来时,它们就会停止工作。也许这是一个简单和/或的情况,它可以像您所期望的那样使用简单谓词,而对于需要一致结果的情况,这是一个更高级的选项?
(defmacro dkdc-or [& key-pred-forms]
  `(s/and (s/or ~@key-pred-forms) (s/conformer second)))