【问题标题】:How do I do automatic data serialization of data objects?如何对数据对象进行自动数据序列化?
【发布时间】:2010-04-22 11:49:21
【问题描述】:

具有某种反射/内省的语言的一大好处是可以从各种来源自动构造对象。

例如,在 Java 中,我可以使用相同的对象来持久化到数据库(使用 Hibernate)、序列化为 XML(使用 JAXB)以及序列化为 JSON(json-lib)。你可以在 Ruby 和 Python 中做同样的事情,通常也遵循一些简单的 Java 属性或注释规则。

因此我不需要很多“域传输对象”。我可以专注于我正在工作的领域。

在 Haskell 和 Ocaml 等非常严格的 FP 中,这似乎是不可能的。 特别是哈斯克尔。我唯一看到的是做某种预处理或元编程(ocaml)。你是否接受了你必须从底部向上进行所有转换?

换句话说,您必须做很多无聊的工作才能将haskell 中的数据类型转换为JSON/XML/DB Row 对象,然后再转换回数据对象。

【问题讨论】:

  • “在非常严格的 FP [语言] [..] 中这是不可能的”——您遇到的问题不是由函数式编程引起的,而是由 Haskell/OCaml 的其他特性/限制引起的.
  • 很公平。我应该说代数编译类型安全语言。是的,在 lisp 之类的东西中,这可能不是问题。严格 FP 的定义有点松散。即使使用像 Scala 这样你确实有反射的语言,首选的方法是“解析”数据(参见游戏 2 的 anorm)。
  • 另外@mattfenwick 我不确定如果从标题中删除 Haskell 并搞砸谷歌,我是否喜欢你的编辑。这没有

标签: haskell serialization ocaml


【解决方案1】:

我无法与 OCaml 交谈,但我想说 Haskell 的主要困难在于 反序列化需要提前知道类型——没有通用的方法可以从格式中机械反序列化,找出结果值是什么,然后从那里开始,这在具有不健全或动态类型系统的语言中是可能的。

抛开类型问题,在 Haskell 中序列化数据有多种方法:

  • 内置类型类Read/Show(反)将代数数据类型和大多数内置类型序列化为字符串。行为良好的实例一般应该是read . show 等价于id,并且show 的结果可以被解析为构造序列化值的Haskell 源代码。

  • Hackage上可以找到各种序列化包;通常,这些要求要序列化的类型是某个类型类的实例,包为大多数内置类型提供实例。有时他们只需要一个可自动派生的类型具体化、反射元编程Data 类的实例(其迷人的完全限定名称是Data.Data.Data),或者提供模板Haskell 代码来自动生成实例。

  • 对于真正不寻常的序列化格式——或者像前面提到的那样创建自己的包——可以使用最大的锤子,有点像ReadShow 的“老大哥” : 解析和漂亮的打印。两者都有大量的包可用,虽然一开始可能听起来很吓人,但实际上在 Haskell 中解析和漂亮的打印是非常轻松的。

对 Hackage 的一瞥表明已经存在各种格式的序列化包,包括二进制数据、JSON、YAML 和 XML,尽管我没有使用过它们中的任何一个,因此我无法亲自证明它们的工作情况。以下是一份非详尽的清单,可帮助您入门:

  • binary:面向性能的序列化到懒惰ByteStrings
  • cereal:类似于二进制,但接口略有不同,并使用严格的ByteStrings
  • genericserialize:通过内置元编程进行序列化,输出格式可扩展,包括 R5RS sexp 输出。
  • json:JSON 数据的轻量级序列化
  • RJson:通过内置元编程序列化为 JSON
  • hexpat-pickle: 序列化为 XML 的组合器,使用“hexpat”包
  • regular-xmlpickler:使用“常规”包将递归数据结构序列化为 XML

唯一的另一个问题是,不可避免地,并非所有类型都是可序列化的——如果没有其他问题,我怀疑您将很难序列化多态类型、存在类型和函数。

【讨论】:

  • 感谢您提供的所有信息。我真的很想给你正确的答案,但我正在寻找更“自动”的东西,似乎你必须进行预处理。
  • @Adam Gent:嗯,据我所知,使用内置通用元编程的包几乎是自动的,只需要Data 和/或Typeable 的实例,两者都是可以由 GHC 自动导出。所需要的只是将deriving (Data, Typeable) 子句添加到任何data/newtype 定义中,就像经常为ShowEq 等使用自动派生实例一样。
  • 该死的为什么我不能给两个人正确的答案!是的,你的例子看起来不错。
  • 我想补充一点,有一个更新的库aeson(支持使用Data派生实例的自动实例以及使用DeriveGeneric衍生的实例)。它可能是 json 的继承者。
【解决方案2】:

对于它的价值,我认为 OCaml 中的预处理器解决方案(如 sexplib、binprot 和 json-wheel 等)非常棒(我认为人们使用 Template Haskell 做非常相似的事情)。它比反射效率高得多,也可以以自然的方式调整到个别类型。如果您不喜欢给定类型 foo 的自动生成的序列化程序,您可以随时编写自己的序列化程序,它非常适合包含 foo 作为组件的类型的自动生成的序列化程序。

唯一的缺点是您需要学习 camlp4 才能为自己编写其中的一个。但是使用它们非常容易,一旦您将构建系统设置为使用预处理器。就像在类型定义的末尾添加with sexp 一样简单:

type t = { foo: int; bar: float }
with sexp

现在你有了你的序列化器。

【讨论】:

    【解决方案3】:

    你想要的

    做很多无聊的工作来将haskell中的数据类型转换为JSON/XML/DB Row对象并再次转换为数据对象。

    在 Haskell 中有很多方法可以序列化和反序列化数据类型。例如,您可以使用,

    以及其他常见的共振峰(protocol buffersthrift、xml)

    每个包通常/通常都带有一个宏或派生机制,以允许您例如导出 JSON。以 Data.Binary 为例,请参阅之前的答案:Erlang's term_to_binary in Haskell?

    一般的答案是:我们在 Haskell 中有许多很棒的序列化包,我们倾向于使用现有的类“派生”基础设施(使用泛型或模板 Haskell 宏来进行实际派生)。

    【讨论】:

      【解决方案4】:

      我的理解是,在 Haskell 中序列化和反序列化的最简单方法是从 ReadShow 派生。这很简单,并不能满足您的要求。

      不过,HXTText.JSON 似乎可以满足您的需求。

      【讨论】:

        【解决方案5】:

        通常的方法是使用Data.Binary。这提供了基本的序列化能力。数据类型的二进制实例很容易编写,并且可以很容易地用更小的单元构建。

        如果你想自动生成实例,那么你可以使用 Template Haskell。我不知道有什么包可以做到这一点,但如果已经存在一个包,我不会感到惊讶。

        【讨论】:

          猜你喜欢
          • 2015-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-07-22
          • 1970-01-01
          • 1970-01-01
          • 2016-06-17
          相关资源
          最近更新 更多