【问题标题】:Override poorly encapsulated instance in Haskell在 Haskell 中覆盖封装不佳的实例
【发布时间】:2018-12-14 02:15:53
【问题描述】:

我的程序依赖于一个库,该库将我提供的 JSON 解码为其内部数据类型。

库试图封装太多。它隐藏了连接细节、数据序列化格式和底层使用的 RPC,因此易于使用。

问题是库拒绝了我必须在我的环境中处理的 JSON。换句话说,它拒绝处理 JSON 负载的常见错误,例如大写/小写差异、意外但无害的键、可恢复的数字/字符串编码错误。

我不能依赖newtype 技巧,因为库希望使用具体的数据类型——不是我的。我需要更改它用于反序列化的“内部”类实例。

没有更好的主意,我分叉了该库,并将其添加为从本地目录构建的依赖项(还必须删除与 stack 相关的所有内容,以便构建会引起注意)。

数据类型未更改,仅更改了序列化格式,使此更改与手头的问题无关。

有没有更好的方法来覆盖库提供的类实例定义?

【问题讨论】:

  • 这里有一个有趣的问题,但它可以更具体。
  • 我有意寻求解决将预定义实例与用户可能合理希望在不破坏宇宙的情况下进行更改的库捆绑在一起的一般问题的答案。
  • 好的,但这仍然应该以允许明确答案的方式表达出来,否则问题太宽泛
  • 您已经描述了您的问题是什么,以及您为解决问题所做的工作。由于我们看不到您的代码,因此我们无法评论其中的任何部分。

标签: haskell


【解决方案1】:

我遇到过几次类似的问题,这很烦人。如果您还没有,可以考虑一些选项:

  1. 我们希望库提供 Haskell 组合器来构建内部类型。然后你可以包装类型并提供一个替代的FromJSON 实例:

    newtype WrappedT = WrappedT { toT :: Library.T }
        deriving (All, The, Classes, You, Care, About)
    
    instance FromJSON WrappedT where
        -- better instance
    
  2. 对 JSON 进行预规范化,即编写一个 JSON-to-JSON 层来删除不可接受的位。

  3. 如果您不想维护分叉,请向作者推送 PR,在 .Internal 模块中公开内部结构,然后您可以执行解决方案 1。这将保持兼容性,同时仍允许您进行更改。 (我个人也认为这样的“软封装”比更常见的“刚性封装”更适合社区)

如果您提供有关问题的更多详细信息,您可能会想到其他解决方案。

【讨论】:

  • 第一个解决方案是非常强大的解决方案,因为我可以包装整个 API!丑陋但可行!现在,这让我意识到这是库的双重设计问题,因为它对我隐藏了 RPC。
  • 我将此标记为已接受的答案,因为 GHC 中似乎没有“链接阶段”实例覆盖机制。
猜你喜欢
  • 2017-03-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-04-04
  • 1970-01-01
相关资源
最近更新 更多