2024 Clojure 状态调查! 中分享您的看法。

欢迎!请查看 关于 页面了解相关信息。

0
Spec
{{(clojure.spec/valid? :clojure.spec/any :clojure.spec/invalid)}} 返回 {{false}}

这个问题很严重,如果有人想编写像 {{=}} 这样的核心函数的 spec,该函数本身就会用到 spec。我观察到了这个错误,因为我为 {{assoc}} 编写 spec。

一个可能的解决方案可能是内部使用一个 {{(Object.)}} 标志,仅在 API 边界使用 {{:clojure.spec/invalid}}。但我还没有深入思考这个问题。

9 个回答

0
_评论由 akiel 提出_

我遇到了另一个与此问题相关的情况。无法测试适用于 conformer 的谓词的返回值,因为它应该返回 {{:clojure.spec/invalid}} 本身。


(ns coerce
  (:require [clojure.spec :as s]))

(s/fdef parse-long
  :args (s/cat :s (s/nilable string?))
  :ret (s/or :val int? :err #{::s/invalid}))

(defn parse-long [s]
  (try
    (Long/parseLong s)
    (catch Exception _
      ::s/invalid)))

0
_评论由 akiel 提出_

在 alpha 10 中,去除 {{:clojure.spec/any}} 并引入 {{any?}} 后,没有变化。
0
by

评论由:seancorfield 提出

另一个来自 Slack 的示例,与此相关

(if-let [a 1] ::s/invalid)

由于 {{::s/invalid}} 会导致 {{if-let}} 的规范认为 {{then}} 表达式不符合规范,因此编译(宏展开)失败。

解决方案

(if-let [a 1] '::s/invalid)

0
by

评论由:ambrosebs 提出

野外的另一个示例:https://github.com/pjstadig/humane-test-output/pull/23

宏重写

(is (= ::s/invalid ..))

改为

(let [a ::s/invalid] ...)

导致了一些非常奇怪的错误。

0
by

评论由:akiel 提出

可以通过直接不在代码中使用 ::s/invalid 来解决宏问题。我认为一般情况下,最好用 s/invalid? 断言。

而不是写

(= ::s/invalid ...)

应该使用

(s/invalid? ...)

但我不知道如何解决有 ::s/invalid 的数据验证问题。 identical? 函数的规范就是一个例子。

(s/fdef clojure.core/identical? :args (s/cat :x any? :y any?) :ret boolean?)

不工作。

0
by

评论由:jcr 提出

请使用 sumtypes 而不是“魔术”值来指示成功或失败。例如,

(s/conform any? ::s/invalid) ;=> [:ok ::s/invalid] (s/conform int? ::s/invalid) ;=> [:failure #::s{:problems ... :spec ... :value ...}]

请注意,返回值应为 clojure.lang.MapEntry 的实例,以便在这些函数上工作。然而,如果您不希望返回解释映射,则返回向量 {{[:ok value]}} 和 {{[:failure]}}(没有第二个元素)也能工作。

由于规范处于公开测试阶段,修复 API 还不晚。

相关:CLJ-2115

0
_评论由:borkdude_发表

这也是一个像Cursive这样的工具REPL中的问题。重放


(ns assoc.core
  (:require
   [clojure.spec.alpha :as s]
   [clojure.spec.test.alpha :as stest]))

(s/fdef clojure.core/assoc
  :args (s/cat :map (s/nilable associative?)
               :key any? :val any? :kvs (s/* (s/cat :ks any? :vs any?)))
  :ret associative?)

(stest/instrument `assoc)

(s/conform string? 1)


在Cursive REPL中评估此命名空间时得到


打印返回值时出错(ExceptionInfo)在 clojure.spec.test.alpha/spec-checking-fn$conform! (alpha.clj:132)。
对clojure.core/assoc的调用没有符合规范。


在没有Cursive的情况下,通过评估上述和这个来重现问题


(defn tooling-repl
  ([] (tooling-repl {}))
  ([state]
   (let [l (read-line)
         evaled (eval (read-string l))]
     (prn evaled)
     (recur (assoc state
                   :*1 evaled
                   :*2 (get state :*1))))))

;; 现在在REPL中输入:`(s/conform string? 1)`
(with-redefs [read-line (constantly "(s/conform string? 1)")])
  (tooling-repl)
0

评论由:borkdude

我按如下方式修改了speculative中的 ::any 规范

`
(s/def ::any
(s/with-gen

(s/conformer #(if (s/invalid? %) ::invalid %))
#(s/gen any?)))

`

0
参考:[https://clojure.atlassian.net/browse/CLJ-1966](https://clojure.atlassian.net/browse/CLJ-1966)(akiel报告)
...