Clojure规范-与规范/一起发布或嵌套在规范/和中
我最近在试用Clojure规范,遇到了一条意外的错误消息。我发现,如果你有一个等级库/或嵌套在等级库/中,然后等级库函数在等级库/或分支之后,会传递一个一致的值,而不是顶级值 您可以在此处“v”的打印值中看到这一点(人为示例): 我认为这可能是spec/and的文档字符串故意造成的: 采用谓词/规范形式,例如 (s/甚至?#(<%42)) 返回返回符合条件的值的规范<强>连续 一致的值通过其余谓词传播。 但这对我来说似乎有悖常理,因为这会妨碍规范谓词的重用,因为它们需要编写为接受“[]” 如果有多个等级库/或分支,情况会变得更糟:Clojure规范-与规范/一起发布或嵌套在规范/和中,clojure,clojure.spec,Clojure,Clojure.spec,我最近在试用Clojure规范,遇到了一条意外的错误消息。我发现,如果你有一个等级库/或嵌套在等级库/中,然后等级库函数在等级库/或分支之后,会传递一个一致的值,而不是顶级值 您可以在此处“v”的打印值中看到这一点(人为示例): 我认为这可能是spec/and的文档字符串故意造成的: 采用谓词/规范形式,例如 (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
我错过了一些基本的东西吗
但这似乎与我的直觉背道而驰,因为它会妨碍规范谓词的重用
在国际海事组织,这些行为的替代方案吸引力较小:
- 默认情况下,放弃
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)))