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

欢迎!请访问关于 页面以了解更多关于本网站如何运作的信息。

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

如果有人喜欢为像 {{=}} 这样的核心函数编写规范,这些函数是由规范本身使用的,那么这个问题就会变得严重。我在编写 {{assoc}} 的规范时发现了这个错误。

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

9 条回答

0
_由 akiel 提出的评论:

我有一个另一个例子描述的问题出现了。对于适合约束器的谓词,不可能测试其返回值,因为它应该本身返回 {{: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]}}(没有第二个元素)也将有效。

由于spec明确处于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/* (s/cat :ks any? :vs any?)))
  :ret associative?)

(stest/instrument `assoc)

(s/conform string? 1)


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


在 clojure.spec.test.alpha/spec-checking-fn$ Begriff! (alpha.clj:132) 处打印返回值(ExceptionInfo)时出错。
'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(由 akiel 提出)
...