clojure - 实现数据模型以防止常见错误

标签 clojure datamodel

在 Clojure 中实现数据模型似乎有多种方法:

  • 普通内置数据类型( map /列表/集合/向量)
  • 内置数据类型 + 元数据——例如:(type ^{:type ::mytype} {:fieldname 1})
  • 内置数据类型 + 特殊访问器函数(例如,get 将映射中不存在的键抛出异常,而不是静默返回 nil )
  • 默认类型
  • 解构
  • 默认记录
  • 默认协议(protocol)

  • 我们已经到了 map /列表不再适合我们的地步——我们遇到了很多前置条件/​​后置条件可以轻松捕获的错误,但需要很长时间才能找到其他的(而且它是很难为接受嵌套映射/列表/向量的函数编写有效的前置/后置条件)——但我们不确定从上述哪个中进行选择。

    我们有三大目标:
  • 编写惯用的 Clojure 代码
  • 避免花费大量时间寻找愚蠢的类型错误
  • 对我们通过默默地破坏任何东西来更改/重构代码的能力充满信心

  • 我们如何利用 Clojure 的力量来帮助我们?

    最佳答案

    Clojure 文化强烈支持原始数据类型。理所当然的。但是显式类型可能很有用。当你的普通数据类型变得足够复杂和具体时,你基本上有一个没有规范的隐式数据类型。

    依赖构造函数。 以 OOP 的方式,这听起来有点脏,但构造函数只不过是一个可以安全方便地创建数据类型的函数。普通数据结构的一个缺点是它们鼓励动态创建数据。因此,我尝试直接组合我的数据,而不是调用 (myconstructor ...)。如果我需要更改基础数据类型,则有很大的错误可能性以及问题。

    记录是甜蜜点。 由于对原始数据类型大惊小怪,很容易忘记记录可以做很多 map 可以做的事情。可以以相同的方式访问它们。您可以对它们调用 seq。你可以用同样的方式解构它们。绝大多数需要 map 的函数也将接受记录。

    元数据不会拯救你。 我对依赖元数据的主要反对意见是它没有反射(reflect)在平等上。

    user> (= (with-meta [1 2 3] {:type :A})  (with-meta [1 2 3] {:type :B}))
    true
    

    这是否可以接受取决于您,但我担心这会引入新的微妙错误。

    其他数据类型选项:
  • deftype 仅用于创建新的基本或特殊用途数据结构的低级工作。与 defrecord 不同,它并没有带来所有的 clojure 优点。对于大多数工作来说,这不是必要的或不建议的。
  • defstruct 应该被弃用。当 Rich Hickey 介绍类型和协议(protocol)时,他基本上说 defrecord 应该永远是首选。


  • 协议(protocol)非常有用,尽管它们感觉有点偏离(函数+数据)范式。如果您发现自己在创建记录,您也应该考虑定义协议(protocol)。

    编辑 :我发现了之前对我来说并不明显的纯数据类型的另一个优势:如果您正在做 Web 编程,纯数据类型可以有效且轻松地转换为 JSON 和从 JSON 转换。 (执行此操作的库包括 clojure.data.json、clj-json 和我最喜欢的 cheshire)。对于记录和数据类型,这项任务相当烦人。

    关于clojure - 实现数据模型以防止常见错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7905547/

    相关文章:

    haskell - Hindley-Milner 中的 `Let` 推理

    clojure - 如何在 Clojure 中实现自动完成示例?

    python - 如何在 swift 3 中集成 CoreML iOS 项目的自定义数据模型

    jsf - p :commandButton with p:fileDownload and no ajax only works in second click

    shell - elisp 解析异步 shell 命令的输出

    recursion - 成员?在无限列表上运行

    clojure - 如何在 clojure/leiningen 中请求 java 类

    Excel VBA 将表添加到数据透视表数据模型

    ios - 我可以忽略有关太多属性的 Cora Data 警告吗?

    python - __getitem__, __setitem__ 多个键