Clojure Spec 关于简单参数匹配的问题

Problem with Clojure Spec about simple parameter matching

我正在为 Clojure(script) 规范苦苦挣扎。 稍微查了一下是什么地方出问题了,但是解决不了

(defn filter-ids
  [[items fields] _]
  (let [ids
        (for [item items
              field-tags (vals fields)
              :let [item-tags (-> item second :tags)
                    item-id (first item)]
              :when (and
                     (seq field-tags)
                     (empty? (set/difference field-tags item-tags)))]
          item-id)]
    (into #{} ids)))

以上代码是我试图定义规范的。 (fdef)

我定义了规范

(spec/def :common/id (spec/and
                      keyword?
                      #(-> %1 name js/parseInt nat-int?)))

(spec/def :common/label string?)

(spec/def :common/tags (spec/coll-of string? :kind set?))

(spec/def :common/item (spec/keys :req-un [:common/label :common/tags]))


(spec/fdef filter-ids
  :args (spec/cat
         :useful (spec/cat
                  :items (spec/map-of :common/id :common/item)
                  :fields (spec/map-of :common/id :common/tags))
         :useless any?)
  :ret (spec/coll-of :common/id :kind set?))

而当我运行用仪器时,出现错误。

(stest/instrument `filter-ids)


(filter-ids [{:0 {:label "task0" :tags #{"one" "two"}}}
             {:0 #{"three"}, :1 #{"one"}}]
            nil)


; Execution error - invalid arguments to taggy.states.subs/filter-ids at (<cljs repl>:1).
[{:0 {:label "task0", :tags #{"two" "one"}}} {:0 #{"three"}, :1 #{"one"}}] - failed: map? at: [:useful :items]

似乎规范认为第一个参数需要是地图,这不是我想要的。

当我在下方点赞时,它不会抱怨地图?。 (虽然仍然是一个错误,因为它根本无效)

(filter-ids {{:0 {:label "task0" :tags #{"one" "two"}}} 1
             {:0 #{"three"}, :1 #{"one"}} 2}
            nil)

我是新手,真的需要一些帮助才能继续前进。

谢谢。

spec/cat 是一个“序列正则表达式”,如果将它嵌套在另一个 spec/cat.

中,它会“展开”

您可以将内部 spec/cat 调用包装在 spec/spec 调用中,以防止展开,或者您可以切换到 spec/tuple(并删除 :items:fields 个标签):

(spec/fdef filter-ids
  :args (spec/cat
         :useful (spec/spec (spec/cat
                              :items (spec/map-of :common/id :common/item)
                              :fields (spec/map-of :common/id :common/tags)))
         :useless any?)
  :ret (spec/coll-of :common/id :kind set?))
;; or
(spec/fdef filter-ids
  :args (spec/cat
         :useful (spec/tuple
                  (spec/map-of :common/id :common/item)
                  (spec/map-of :common/id :common/tags))
         :useless any?)
  :ret (spec/coll-of :common/id :kind set?))

这两个都可以。您选择哪一个可能取决于您在错误消息中想要的信息(我认为前者会在您出错时提供更多上下文,因为 :items:fields 标签)。