Clojure规范-规范中的问题,或嵌套在规范中,并且

时间:2018-06-24 08:00:35

标签: clojure clojure.spec

我最近一直在尝试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

我认为这可能是来自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

我在这里错过了一些基本的东西吗?

1 个答案:

答案 0 :(得分:6)

  

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

IMO这些行为的替代方法吸引力较小:

  • 默认丢弃s/or的合格标签 。如果愿意,我们总是可以将其丢弃,但我们不希望clojure.spec为我们做出决定。 Spec假设我们想知道哪个s/or分支匹配。
  • 请勿在{{1​​}}中传递符合条件的值,以规范/谓词可组合性为代价。

幸运的是,如有必要,我们可以丢弃s/and标签。这是两个选项:

  • s/or中包装s/or。多亏了glts在下面的评论让我想起了这个(未记录的)功能!

    s/noncomforming
  • (s/valid? (s/and (s/nonconforming (s/or :s string? :v vector?)) empty?) "") => true 的{​​{1}}规范,其中有一个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/or),海事组织(IMO)在后续谓词中拥有该知识通常更为有用。我有兴趣看到这种规格的更实际的用例,因为可能有更好的规格说明。