如何对数据对象进行自动数据序列化?

时间:2010-04-22 11:49:21

标签: haskell serialization ocaml

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

例如,在Java中,我可以使用相同的对象来持久化到db(使用Hibernate),序列化为XML(使用JAXB),以及序列化为JSON(json-lib)。您可以在Ruby和Python中执行相同的操作,通常也遵循一些简单的Java属性或注释规则。

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

似乎在非常严格的FP中,如Haskell和Ocaml,这是不可能的。 特别是Haskell。我唯一看到的是进行某种预处理或元编程(ocaml)。刚刚接受你必须从下到上进行所有转换吗?

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

5 个答案:

答案 0 :(得分:28)

我不能和OCaml说话,但我会说Haskell的主要困难是反序列化需要事先知道类型 - 没有通用的方法从格式中进行机械反序列化,找出结果值是什么,并从那里开始,就像在有不健全或动态类型系统的语言中一样。

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

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

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

  • 对于真正不寻常的序列化格式 - 或者像前面提到的那样创建自己的包 - 人们可以找到最大的锤子,有点像Read和{{大哥哥' {1}}:解析和漂亮打印。两者都可以使用许多软件包,虽然它起初可能听起来令人生畏,但在Haskell中,解析和漂亮打印实际上是非常轻松的。

对Hackage的一瞥表明已经存在各种格式的序列化包,包括二进制数据,JSON,YAML和XML,虽然我没有使用它们,所以我无法亲自证明它们的工作情况。这是一个非详尽的列表,可以帮助您入门:

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

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

答案 1 :(得分:5)

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

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

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

现在你有了序列化器。

答案 2 :(得分:5)

你想要

  

做很多无聊的工作,将haskell中的数据类型转换为JSON / XML / DB Row对象,然后再转换回数据对象。

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

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

每个包经常/通常附带一个宏或派生机制,以允许您例如派生JSON。例如,对于Data.Binary,请参阅前面的答案:Erlang's term_to_binary in Haskell?

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

答案 3 :(得分:4)

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

然而,HXTText.JSON似乎提供了您所需要的功能。

答案 4 :(得分:3)

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

如果要自动生成实例,则可以使用Template Haskell。我不知道有任何方法可以做到这一点,但如果已经存在,我不会感到惊讶。