3

我想用keys/编写一个规范,keys*但能够内联值规范,这是design 不支持的,我得到了它背后的原因。但是,当地图有特定上下文时,有时您确实希望(或只是通过旧版或第 3 方)键和值之间的耦合。

我对规范还是陌生的,这只是我第一次将它与现有项目集成,它不断给我带来问题,因为它假设太多,特别是因为上面提到的原因。例如,想象一个描述时间段并有一个until日期键的映射,在同一个 ns 中,有一个用于列表处理的映射,还有一个until带有谓词函数的映射。我现在需要为甚至不存在的命名空间手动编写完全命名空间的键(aliasing 很可爱,但它必须在多个命名空间/文件中不断复制)。除了烦人之外,我觉得它也容易出错。

另一个keys/keys*假设太多的地方是我什至想要关键字作为我的键。我现在正在为非程序员但技术用户编写 DSL,底线是我想指定一个带有符号作为键的映射。这似乎不受任何支持。

有什么我没有得到的吗?还是规范真的缺少基本功能?

4

2 回答 2

4

您可以使用 map-of 指定带有符号作为键的映射:

(s/def ::sm (s/map-of symbol? any?))

或通过将地图指定为条目集合:

(s/def ::sm (s/every (s/tuple symbol? any?) :kind map? :into {}))

后者特别有趣,因为您可以使用s/或许多不同类型的元组来描述更有趣的地图,而不是单个元组。您甚至可以通过这种方式将这些符号连接到其他现有规范:

(s/def ::attr1 int?)
(s/def ::attr2 boolean?)
(s/def ::sm (s/every (s/or :foo (s/tuple #{'foo} ::attr1)
                           :bar (s/tuple #{'bar} ::attr2))
              :kind map? :into {}))
(s/valid? ::sm {'foo 10 'bar true}) ;; => true
于 2016-12-20T16:07:23.953 回答
1

我现在需要为甚至不存在的命名空间手动编写完全命名空间的键

我也一直在使用这种方法,我认为我实际上更喜欢它,而不是我喜欢确保您的关键字的名称空间始终对应于真正的 Clojure NS 表单。我使用关键字 like:business-domain-concept/a-name而不是:my-project.util.lists/a-name.

您可以使用不映射到任何 Clojure NS 的任意名称空间创建关键字。例如,在您的until情况下,您可以定义一个:date/until描述日期的规范,以及一个:list/until描述列表处理映射字段的规范(也许有一个更好的名称)。

听起来您已经知道这种任意关键字命名空间方法 - 特别是,我认为它容易出错,因为您是手动输入这些内容,并且如果您输入,规范似乎不会窒息你s/keys的一个:fate/until意外。不过,FWIW,我认为您目前正在感受到命名空间关键字旨在解决的痛苦:您在一个 Clojure 文件中,您有两个带有名为 的键的映射until,它们意味着两个完全不同的东西。

我现在正在为非程序员但技术用户编写 DSL,底线是我想指定一个带有符号作为键的映射。

我认为map-of是你想要的:

user=> (s/def ::valid-symbols #{'foo 'bar 'baz})
:user/valid-symbols
user=> (s/def ::symbol-map (s/map-of ::valid-symbols int?))
:user/symbol-map
user=> (s/valid? ::symbol-map {'foo 1 'bar 3})
true
user=> (s/valid? ::symbol-map {'foo 1 'quux 3})
false
于 2016-12-20T15:54:24.463 回答