我最近一直在尝试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
我在这里错过了一些基本的东西吗?
答案 0 :(得分:6)
但这对我来说似乎违反直觉,因为这会阻碍规范谓词的重用
IMO这些行为的替代方法吸引力较小:
s/or
的合格标签 。如果愿意,我们总是可以将其丢弃,但我们不希望clojure.spec为我们做出决定。 Spec假设我们想知道哪个s/or
分支匹配。幸运的是,如有必要,我们可以丢弃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)在后续谓词中拥有该知识通常更为有用。我有兴趣看到这种规格的更实际的用例,因为可能有更好的规格说明。