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

欢迎!请在关于页面查看更多关于如何使用本站的信息。

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

如果喜欢为像 {{=}} 这样由spec自身使用的核心函数编写规范,那么这个问题会变得非常严重。我在为 {{assoc}} 编写规范时观察到了这个bug。

可能的解决方案可能是在内部使用一个 {{(Object.)}} sentinal 标志,而在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}}的spec认为{{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? 的函数 spec 是一个很好的例子。

(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]}}(没有第二个元素)也可以。

由于 spec 显式在 alpha 版,修复 api 还不晚。

相关:CLJ-2115

0
_评论由:borkdude_ 发布

这也与Cursive等的tooling 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圆锥! (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
...