问题 Haskell - 操纵/扩展不受您控制的ADT


操纵/扩展不受您控制的ADT的最佳方法是什么? (即来自依赖)

这里 是与我的问题相关的数据类型:

我想维护数据的结构,但添加额外的数据(即添加另一种类型),但结构本身不在我的控制之下。我是否必须将数据映射到我自己的此定义版本?

例如,对于结构中的所有段落,我想 Para 成为 Para [Inline] [String] 哪里 [String] 是段落中包含的单词列表(因为它是自己的数据结构)。

我通过端点将这些数据作为JSON提供,我认为我可以解决这个问题的方法是定义我自己的数据 ToJSON 实例,并执行此转换 Para 但是,我无法覆盖实例,因为它已经定义了!我愿意接受一个实际上没有触及的解决方案 Para 键入自己,我只需要一种方法来结合更多的数据 Para 不失任何结构的完整 Pandoc 文件。


12673
2017-11-13 21:49


起源

您是否需要向该类型添加更多构造函数,或者仅向现有构造函数添加新字段? - danidiaz
我还不是100%肯定,但我当然希望能够至少为现有构造函数添加其他字段 - danbroooks
Haskell数据类型是关闭的,所以我不相信你可以在不修改源代码的情况下扩展精确的ADT。您可以将可扩展类型视为一种解决方案。 - jkeuhlen


答案:


但是我无法覆盖实例,因为它已经定义了!

您可以定义包装Pandoc的newtype,然后为其定义自定义ToJSON实例。 query 从 Text.Pandoc.Walk 可以轻松有效地从Para中提取字符串。

您可能考虑的另一件事是创建一个函数,它将Div中的每个Para包装在一个存储在其中一个属性中的字符串中。从您所说的内容来看,这是否适用于您的目的尚不清楚,但定义一个完成此转换的函数会很容易。


7
2017-11-13 23:57





是的,我认为定义自己的 JSON 序列化器可能是最好的方法。你可以定义 JSON 序列化程序没有使用类型类机制,因为Aeson设计得很好(感谢@bos),只需从中定义一个函数 Block ->Value。不幸的是,您似乎必须手动遍历每个案例,至少是嵌套案例 BlockBlockQuoteOrderedList等等。对于其他人,你可以转发 ToJSON

serialize :: Block -> Value
serialize (BlockQuote bs) = object
   [ "type" .= "blockquote"       -- or whatever the encoding is
   , "blocks" .= map serailize bs
   ]
...  -- implement this for every constructor with recursive Blocks
serialize b = toJSON b

它并不好,因为你可能不得不直接重写已编写的内容。考虑到pandoc的设计,我没有看到解决方法(通常AST是通过一种注释来参数化的,例如: 哈斯克尔-SRC-EXTS,或使用一些开放式定点设计,这将允许更聪明的东西)。

一种相当粗略的方式是使用序列化 toJSON,找到的部分 JSON 您想要注释的结构,反序列化该部分并计算注释,重新编译,然后添加您的计算注释。非常难看,但我认为你不必重新实现任何序列化器。如果pandoc有一个 批量 对于递归构造函数,或者非常复杂的序列化,我可能会考虑这一点,但就目前而言,我可能会咬紧牙关并重新实现递归的情况。


4
2017-11-13 23:15