【问题标题】:Clojure Spec - Issue with spec/or nested in spec/andClojure Spec - 与规范/或嵌套在规范/和中的问题
【发布时间】:2018-06-24 08:00:34
【问题描述】:

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

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

(spec/valid? (spec/and (spec/or :always-true (constantly true))
                       (fn [v]
                         (println "v:" v)
                         (constantly true)))
         nil)
v: [:always-true nil]
=> true

我认为这可能是从规范/和的文档字符串故意的:

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

(s/甚至?#(

返回一个规范,该规范返回符合的值。 连续 符合的值通过其余谓词传播。

但这对我来说似乎违反直觉,因为它会妨碍规范谓词的重用,因为它们需要被写入接受“[]”。

如果您有多个规范/或分支,情况会变得更糟:

(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

我在这里遗漏了一些基本的东西吗?

【问题讨论】:

    标签: clojure clojure.spec


    【解决方案1】:

    但这对我来说似乎违反直觉,因为它会妨碍规范谓词的重用

    IMO 对这些行为的替代方案不太有吸引力:

    • 默认丢弃s/or 的符合标签。如果我们愿意,我们总是可以丢弃它,但我们不希望 clojure.spec 为我们做出决定。 Spec 假设我们想知道与哪个s/or 分支匹配。
    • 不要在 s/and 中传递符合要求的值,以牺牲规范/谓词的可组合性为代价。

    幸运的是,如果需要,我们可以丢弃 s/or 标记。这里有两个选项:

    • s/or 包裹在s/noncomforming 中。感谢下面 glts 的评论提醒我这个(未记录的)功能!

      (s/valid?
        (s/and
          (s/nonconforming (s/or :s string? :v vector?))
          empty?)
        "")
      => true
      
    • s/and s/or 规范与 s/conformer 丢弃标签。

      (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/ors/alt)的数据编写规范,并且您正在将有效备选方案“流动”到后续谓词中(s/and ),IMO 在后续谓词中拥有该知识通常更有用。我有兴趣看到这种规范的更现实的用例,因为可能有更好的方法来规范它。

    【讨论】:

    • 你也可以使用s/nonconforming代替conformer。
    • Taylor 很高兴阅读您的答案,总是真实 有理由地回答,而不是可能解决问题但没有贡献的快速而肮脏的代码去理解。谢谢!
    • 感谢您抽出宝贵的时间撰写出色的答案。我理解你的观点,但最终我可以看到很多人从小处着手,用简单的谓词建立规范,然后,正如我发现的那样,当你尝试将它们与 and/or 操作结合起来时,它们将停止工作。也许这是一个简单的和/或的情况,它可以像您期望的那样使用简单的谓词和更高级的选项来处理需要一致结果的情况?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 2017-12-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多