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

欢迎!请查看关于页面,了解更多此网站的工作方式。

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

如果喜欢为如{{=}}这样的核心函数编写规格(它们由spec使用),这个问题会变得严重。当我为{{assoc}}编写规格时,我遇到了这个bug。

可能的解决方案可能是内部使用一个{{(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_发表的评论

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

由:seancorfield发表的评论

与这相关的Slack中的另一个示例

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

编译失败(宏展开)是因为 {{::s/invalid}} 让 {{if-let}} 的规范误以为 {{then}} 形式不符合规范。

解决方案

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

0

评论者:ambrosebs

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

宏重写

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

转为

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

导致了非常奇怪的错误。

0

评论者: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

评论者:jcr

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

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

注意,返回值应该是一个 clojure.lang.MapEntry 的实例,以便可以在其中使用 {{key}} 和 {{val}}。然而,如果不希望返回 explain-map,则返回包含 {{[:ok value]}} 和 {{[:failure]}}(没有第二个元素)的向量也可以正常工作。

由于规范处于公开测试阶段(alpha),修改 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/*. 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).
函数调用了未符合规范的诊断符。


即使在没有手写输入的情况下,通过计算上述内容也可以复现问题。


(defn 工具替换
  ([] (工具替换 {}))
  ([状态]
   (let [行 (read-line)
         已计算 (eval (read-string 行))]
     (prn 已计算)
     (recur (assoc 状态
                   :*1 已计算
                   :*2 (get 状态 :*1))))))

;; 现在在REPL中输入: (s/conform string? 1)
(with-redefs [read-line (constantly "(s/conform string? 1)")]
  (工具替换))
0

评论:borkdude

我对speculative中的{{::any}}规范进行了以下修改

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

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

`

0
参考:[a kie 关联 CLJ-1966](https://clojure.atlassian.net/browse/CLJ-1966 "由 akiel 报告的柳荫问题")
...