haskell - 避免在 Haskell 中重复实例声明
问题描述
我的问题似乎与这个密切相关 。
我的代码解析一个 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
,它就开始变得有价值了。
注意:我没有测试过这些。