如何Clojure.Spec引用类型(如原子)?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何Clojure.Spec引用类型(如原子)?相关的知识,希望对你有一定的参考价值。
我想知道我是如何规定一个函数,它有一个参数,在一个原子中保存一个映射。
(defn do-something [a]
(prn (vals @a)))
这些显然不起作用:
(s/fdef do-something
:args (s/cat :a map?))
我如何规定a
是地图的参考?
答案
别。 clojure.spec是关于指定数据的结构,原子是状态,而不是数据。并非每个功能都必须具有(或检查)规范。
我处理有状态数据的一般建议是:
- 定义您的数据
- 定义纯函数以获取并返回数据
- 为这些数据函数创建规范
- 仅在尽可能少的地方使用那些纯函数来操纵原子
通过一些小心,您通常可以减少将原子取回或返回0的函数数量(通过关闭它所管理的位置的原子),这是一个非常有价值的目标。
另一答案
你没有。出于一个原因,它不是线程安全的。如果你以某种方式确定原子包含一个地图,它可能会在你检查原子的时候变成一个整数,并继续你的功能。
但是,一种选择是为原子提供验证器。您可以轻松地使用partial来执行此操作:(set-validator! my-atom (partial s/valid? :my-spec))
。现在原子将无法更新,除非该值符合:my-spec。
另一种选择是为更新原子的所有函数添加验证逻辑。这两种方法中哪一种最有效取决于应用。
另一答案
您可以使用with-gen
,自定义谓词和自定义生成器:
(require '[clojure.spec.alpha :as spec]
'[clojure.spec.gen.alpha :as gen])
(defn memoize! [memo key distance]
"Memoizes the distance at the given key and returns the distance"
(swap! memo assoc key distance)
distance)
(spec/def ::word
(spec/and string? (complement nil?)))
(defn map-atom? [o]
(and (instance? clojure.lang.IAtom o)
(map? @o)))
(def map-atom-gen
(gen/fmap
(fn [_] (atom {}))
(gen/int)))
(spec/def ::map-atom
(spec/with-gen map-atom?
(constantly map-atom-gen)))
(spec/fdef memoize!
:args (spec/tuple ::map-atom
(spec/coll-of ::word :type vector? :count 2)
nat-int?)
:ret nat-int?
:fn (fn [{[memo key distance] :args, retval :ret}]
(= distance (@memo key) retval)))
以上是关于如何Clojure.Spec引用类型(如原子)?的主要内容,如果未能解决你的问题,请参考以下文章