在< Jahresbericht Clojure 2024>中分享您的想法![2024 Clojure调查问卷]!

欢迎!请参阅关于页面了解有关如何工作的更多信息。

0 投票
Spec

你好,我到这里来报告我认为是我一周内第二次出现的spec功能中的问题。

如果已经报告为错误,我表示歉意,但我基本上无法理解/预期的最后一个调用触发错误 -::id-map规范并不需要最后对::other进行检查。

(ns repro-spec.test
  (:require [clojure.spec.alpha :as s]
            [clojure.spec.test.alpha :as st]))

(s/def ::impl any?)
(s/def ::id string?)
(s/def ::other number?)

(s/def ::id-map (s/keys :req [::id]))

(s/fdef delete-impl
  :args (s/cat :impl ::impl
               :id-map ::id-map))

(defn delete-impl [_ id-map]
  (println (str "This deletes " (::id id-map)))
  id-map)

(st/instrument)

(delete-impl {} {::id "test"})
;; prints "This deletes test"

(delete-impl {} {::id "test" ::other "ignore me"})
;; Execution error - invalid arguments to repro-spec.test/delete-impl at (REPL:27).
;; "ignore me" - failed: number? at: [:id-map :repro-spec.test/other] spec: :repro-spec.test/other

我是做错了什么吗?

1 答案

0 投票

这是按设计进行的,并在文档中描述:https://clojure.org/guides/spec#_entity_maps

当在映射上检查一致性时,它会做两件事 - 检查是否包含必需的属性,并检查每个已注册的键都有一个符合规范的价值。我们稍后就会看到可选属性可以有什么用。 另外请注意,所有属性都是通过键进行检查的,而不仅仅是在:req和:opt键中列出的属性。因此,一个裸的(s/keys)是有效的,并将检查映射的所有属性,而不检查哪些键是必需的或可选的。

(强调部分)

by
果然在里面!TIL :D

你能解释一下它的逻辑吗?看起来`s/keys`可以用来“限制”需要检查的范围——也就是说,请只检查这些键——但是检查却在所有键上执行?
我认为关于这一点,Alex可能更有发言权,但我的理解是,有资格的Spec名称是为了给出全局名称的全局意义,而`s/keys`是为了确定是否需要特定的键(`:opt`本质上是用于文档的,表示“我也可能使用这些键”)。必要性是与名称的全局意义正交的。

请注意,对于`:req-un`和`:opt-un`这不是真的,因为这些键在映射中未经资格化,没有全局意义——只有它们在`s/keys`中的名称资格化(关联到有资格的Spec名称)赋予的含义。
> 需要与名称的全局意义正交。

非常感谢你的解释,这正是我所缺少的。全局事项确实会使孤立推理更困难(个人看法,也许很明显)。我现在明白为什么`spec2`中的`select`等问题会出现了。
你可能发现阅读规范理据和指南有所帮助,以便填补这些问题的一些答案

* https://clojure.org/about/spec
* https://clojure.org/guides/spec
by
第一个链接很有帮助,谢谢。
...