haskell - 在 haskell 中运行时反序列化为不同类型

标签 haskell types aeson

背景

我正在使用 Aeson 库来存储和检索文件中的值。我正在使用 Typeable (和 TypeRep)来标记数据,因此我很清楚它将正确解析。

我有一个类,其中类的每个成员都有一个需要时间(整数)并更新自身的函数,即:

class Update a where
  update :: Integer -> a -> a

文件中存储的所有值都是 Update 类的实例。

问题 我想迭代文件更新每个值并写入一个新文件。我想让程序在运行时确定数据 block 的数据类型是什么,使用 fromJSON 创建该类型的值,对其运行 update ,然后写回来。类型检查器认为这是一个糟糕的想法,因为它无法在编译时对 fromJSON 调用进行静态类型检查,因此无法从 Update 类字典中获取正确的条目。

有没有办法使用 Typeable(或 Data)让类型检查器做正确的事情?有更好的选择吗?

<小时/>

解决这个问题的唯一想法是创建所有可更新类型的联合数据类型,然后使用 case 语句来解析标记并选择正确的构造函数。我对这个解决方案不太满意,因为我无法在不接触这个联合类型的情况下向更新类添加新类型。

最佳答案

(这更像是一个扩展评论,而不是完整的答案。)

I'm not real happy with this solution because I cannot add new types to the update class without also touching this union type.

我建议实际上重新考虑这个推理。 Haskell 中的类型类表示某种类型具有特定的属性。例如,可以将这些数字相加。这并不意味着程序应该/想要使用这样的属性,该属性是数据类型固有的。而且它们是开放的 - 程序的不同部分可以添加新实例,并且程序的行为不应依赖于独立模块中声明的实例。

您的建议,即自动解析 Update 的所有实例,与上述意义背道而驰。它可能会降低你的程序的可读性,更重要的是,会在将来产生更多问题。如果有人想确定解析部分到底是如何工作的,他必须检查程序的完整源代码并查找 Update 的所有实例。我宁愿提倡局部性 - 程序的含义应该取决于它的“局部环境”。

它也不允许有您不想使用的实例(例如仅用于测试)。它还不允许您拥有 2 个或更多解析例程,每个例程使用一组不同的 Update 实例。

使用 Typeable 标记数据也可能存在问题,因为它不允许您轻松重构代码。如果您需要更改类型,您将无法解析数据。

<小时/>

所以我的建议是拥有这样的联合数据类型,但要简化相应的样板代码。

Aeson 已经让您能够使用 Generic 派生实例。因此您无需担心 FromJSON/ToJSON。您可以使用 Template Haskell 或使用 Generic 为该联合类型编写一次泛型 Upgrade 实例,这样无论联合类型的构造函数数量如何,它都会自动派生。这将使您能够对序列化/反序列化过程进行完全的本地控制,而在修改实例时只需很少的手动工作。

如果您愿意,我还可以举一个如何编写这样的实例的示例。

关于haskell - 在 haskell 中运行时反序列化为不同类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45645748/

相关文章:

haskell - 如何根据 Reader 环境中的设置有条件地解析 JSON?

haskell - 绑定(bind)函数替代方案,无需显式返回 Monad

Haskell 的 Pairs 类型

c++ - C++ 中的表实现

haskell - 是否可以在派生 Generic 的记录数据类型中列出字段的名称和类型?

json - 如何合并 Aeson 对象?

haskell - 用于插值字符串的 Haskell 库

debugging - Haskell 将跟踪重定向到一个文件

haskell - 为什么我的 Haskell 程序以内存不足错误结束?

c - 如何将一个 64 位数字拆分为八个 8 位值?