haskell - 避免在 Haskell 中重复实例声明

标签 haskell instance dry deriving derivingvia

我的问题似乎与this密切相关
一。

我的代码解析一个 yaml 文件,重新排列对象并写入一个新的 yaml 文件。它工作得很好,但其中有一个特别丑陋的部分。

我必须将我的数据结构声明为 FromJson 的实例和 ToJson像这样:

instance FromJSON Users where
  parseJSON = genericParseJSON (defaultOptions { fieldLabelModifier = body_noprefix })
instance ToJSON Users where
  toJSON = genericToJSON (defaultOptions { fieldLabelModifier = body_noprefix })

问题是我必须在 8 个左右的其他情况下重复此操作:
instance FromJSON Role where
  parseJSON = genericParseJSON (defaultOptions { fieldLabelModifier = body_noprefix })
instance ToJSON Role where
  toJSON = genericToJSON (defaultOptions { fieldLabelModifier = body_noprefix })

...
...

我不知道如何避免这种重复。是否有某种方法可以只声明一次这两个函数(例如在一个新类中)并让所有这些数据类型都从它派生?

解决方案(另请参阅 dfeuer 接受的答案):

我个人喜欢这个解决方案。你需要添加
{-# language DerivingVia #-}
{-# language UndecidableInstances #-}

newtype NP a = NP {unNP::a} 

instance (Generic a, GFromJSON Zero (Rep a)) => FromJSON (NP a) where
  parseJSON = fmap NP . genericParseJSON 
    (defaultOptions { fieldLabelModifier = body_noprefix })

instance (Generic a, GToJSON Zero (Rep a)) => ToJSON (NP a) where
  toJSON = genericToJSON (defaultOptions { fieldLabelModifier = body_noprefix }) . unNP

然后你可以像这样声明类型:
data User = User { ... } deriving (Show, Generic)
                         deriving FromJSON via (NP User)
                         deriving ToJSON via (NP User)

最佳答案

这是相当新的DerivingVia扩展是为了,除其他外。

{-# language DerivingVia #-}

newtype NP a = NP {unNP::a}

instance (Generic a, GFromJSON Zero (Rep a)) => FromJSON (NP a) where
  parseJSON = fmap NP . genericParseJSON 
    (defaultOptions { fieldLabelModifier = body_noprefix })

instance (Generic a, GToJSON Zero (Rep a)) => ToJSON (NP a) where
  toJSON = genericToJSON (defaultOptions { fieldLabelModifier = body_noprefix }) . unNP

现在,你可以写
deriving via (NP User) instance FromJSON User

或者
data User = ...
  deriving Generic
  deriving (FromJSON, ToJSON) via (NP User)

等等。

与 leftaroundabout 的答案相比,这并没有节省很多。但是,一旦添加了 toEncoding 的定义,它开始看起来值得。

注意:我没有测试过这些。

关于haskell - 避免在 Haskell 中重复实例声明,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55268631/

相关文章:

haskell 光泽 : render Picture to Bitmap

scala - Monad 与顺序函数调用

haskell - 相互引用的默认类型实例

Javascript:如何隐藏对象的属性?

java - 这是替换 Java 对象的最佳方法吗?

android - 如何压缩重复的 switch 语句

function - 什么是多态λ?

common-lisp - 如何在 Common Lisp 中编写类似的函数?

c++ - 我可以在移动赋值运算符中调用析构函数吗?

c# - 如何将委托(delegate)传递给方法,其中委托(delegate)是非静态的?