clojure.spec人类可读的形状? [英] clojure.spec human readable shape?

查看:79
本文介绍了clojure.spec人类可读的形状?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用clojure.spec,是否可以为嵌套地图定义更易于阅读的规范?以下内容不太好:

With clojure.spec, is there a way to define a more "human-readable" spec for nested maps? The following doesn't read very well:

(s/def ::my-domain-entity (s/keys :req-un [:a :b])
(s/def :a (s/keys :req-un [:c :d]))
(s/def :b boolean?)
(s/def :c number?)
(s/def :d string?)

鉴于一致实体的形状类似

Given that the shape of a conforming entity is something like

{:a {:c 1:d hello}}:b错误}

我的抱怨是,如果规范中有任何嵌套的地图或任何深层结构,则很难阅读规范…因为您要在文件中上下移动键,而且它们不是就地声明。

My complaint is that it becomes hard(er) to read a spec if it has any sort of nested maps or any deep structure… because you are chasing keys up and down a file and they aren’t "in place" declarations.

相比之下,诸如schema之类的东西可以使嵌套语法更具可读性,

To compare, something like schema allows a more readable nested syntax that closely mirrors the actual data shape:

(m / defschema my-domain-entity {:a {:c sc / number:d sc /字符串}:b sc / bool})

可以在clojure.spec中完成吗?

Can this be done in clojure.spec?

推荐答案

规范的价值主张之一是它不具有吸引力定义一个实际的模式。它不会将实体的定义绑定到其组件的定义。引用规范原理

One of spec's value propositions is that it does not attempt to define an actual schema. It does not bind the definition of an entity to the definition of its components. To quote from the spec rationale:


大多数用于指定结构的系统将键集(例如,映射中的键,对象中的字段)的规范与这些键所指定的值的规范相结合。即在这种方法中,地图的模式可能会说:a键的类型为x型,而:b键的类型为y型。这是僵化和冗余的主要来源。

Most systems for specifying structures conflate the specification of the key set (e.g. of keys in a map, fields in an object) with the specification of the values designated by those keys. I.e. in such approaches the schema for a map might say :a-key’s type is x-type and :b-key’s type is y-type. This is a major source of rigidity and redundancy.

在Clojure中,我们通过动态地组成,合并和构建地图来获得力量。我们通常处理可选数据和部分数据,由不可靠的外部源生成的数据,动态查询等。这些映射表示相同键的各种集合,子集,交集和并集,并且通常无论在何处都应具有相同的语义它被使用。在大多数动态情况下,定义每个子集/联合/交集的规范,然后冗余地说明每个键的语义既是反模式,也不可行。

In Clojure we gain power by dynamically composing, merging and building up maps. We routinely deal with optional and partial data, data produced by unreliable external sources, dynamic queries etc. These maps represent various sets, subsets, intersections and unions of the same keys, and in general ought to have the same semantic for the same key wherever it is used. Defining specifications of every subset/union/intersection, and then redundantly stating the semantic of each key is both an antipattern and unworkable in the most dynamic cases.

因此,直接回答这个问题,不,规范不提供这种类型的规范,因为它是专门设计的。您需要权衡在类似模式的定义中应该具有的一定程度的人类可读性,以获得更加动态,可组合,灵活的规范。

So to answer the question directly, no, spec does not provide this type of specification, as it was designed specifically that way. You trade off some level of human readability that you would have in a schema-like definition, for a more dynamic, composable, flexible specification.

尽管这不是您的问题,但请考虑一下使用将实体的定义与其组件的定义脱钩的系统的好处。它是人为的,但是考虑定义一辆汽车(只需使用轮胎和底盘就可以在这里节省空间):

Though it was not in your question, consider the benefit of using a system that decouples the definition of an entity from the definition of its components. It's contrived, but consider defining a car (keeping it simple to save space here, just using tires and chassis):

(s/def ::car (s/keys :req [::tires ::chassis]))

我们定义一次,我们可以将任何想要的轮胎配置放在上面:

We define it once, and we can put any configuration of tires we want on it:

(s/def ::tires (s/coll-of ::tire :count 4))

(s/def ::tire (s/or :goodyear ::goodyear}
                    :michelin ::michelin))

(s/def ::goodyear #{"all-season" "sport" "value"})
(s/def ::michelin #{"smooth ride" "sport performance"})

(s/def ::chassis #{"family sedan" "sports"})

是不同的配置,但都是有效的汽车:

The following are different configurations, but all are valid cars:

(s/valid? ::car {::tires ["sport" "sport" "sport" "sport"]
                 ::chassis "sports"})

(s/valid? ::car {::tires ["smooth ride" "smooth ride"
                          "smooth ride" "smooth ride"]
                 ::chassis "family sedan"})

它是人为的,但很清楚看到将组件定义为与组件组合成的组件分开时具有灵活性。轮胎有自己的规格,即使它们是汽车的组成部分,轮胎的规格也不是汽车的定义。它更冗长,但更灵活。

It's contrived, but clear to see that there is flexibility in defining the components as separate from what the components come together to form. Tires have their own specifications, and their specification is not what defines a car, even though they are components of the car. It's more verbose, but much more flexible.

这篇关于clojure.spec人类可读的形状?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆