你怎么能有两个具有相同字段名称的记录?

时间:2014-11-06 23:13:01

标签: json haskell template-haskell

我正在为JIRA编写JSON服务,并且我遇到了与Haskell命名空间冲突的要求。 我有这个记录

data Assignee = Assignee {name :: Text} deriving Generic
instance ToJSON Assignee

这是由JIRA想要的,不幸的是它想要一个不同的对象使用相同的字段。

data Reporter = Reporter {name :: Text} deriving Generic
instance ToJSON Reporter

我看到了几个选项:

  1. 也许我可以绕过编译器对Haskell模板的抱怨,但是如何?
  2. 我可能根本没有Reporter记录,并在创建故障单后用单独的服务更改记者字段。我知道怎么做,但这是最好的方式吗?
  3. 手动创建JSON对象,但我从此记录中创建它:

      data Fields = Fields 
              { project     :: HashMap Key Project
              , summary     :: Text
              , issuetype   :: HashMap Name Task
              , versions    :: [HashMap Name Text]
              , description :: Text
              , assignee    :: Assignee
              } deriving (Generic)
    
  4. 手工制作这个想法给了我一些感觉。如果我必须的话。

    所以,我现在的问题是,如果除了我提出的方法之外没有其他更好的方式,哪一项是最好的行动方案?

2 个答案:

答案 0 :(得分:7)

最直接的方法是启用-XDisambiguateRecordFields扩展程序。

答案 1 :(得分:6)

如果DisambiguateRecordFields和/或将记录保存在单独的模块中,那就非常适合。

如果没有,那么解决此问题的常用方法是以某种方式为记录字段标签添加前缀,以消除歧义:

data Assignee = Assignee {assigneeName :: Text} deriving Generic
data Reporter = Reporter {reporterName :: Text} deriving Generic

您仍然可以使用GHC Generics来派生JSON转换函数,但您必须对其进行配置以便更改字段标签,例如:

stripPrefix :: Eq a => [a] -> [a] -> [a]
stripPrefix p x = case splitAt (length p) x of
  (y, z)
    | y == p    -> z
    | otherwise -> x

lower :: String -> String
lower []       = []
lower (x : xs) = toLower x : xs

stripPrefixOptions :: String -> Options
stripPrefixOptions p = defaultOptions {
  fieldLabelModifier = lower . stripPrefix p
}

然后你可以说:

data Assignee = Assignee {assigneeName :: Text} deriving Generic
instance ToJSON Assignee where
  toJSON = genericToJSON (stripPrefixOptions "assignee")

data Reporter = Reporter {reporterName :: Text} deriving Generic
instance ToJSON Reporter where
  toJSON = genericToJSON (stripPrefixOptions "reporter")

在GHCi中进行测试:

GHCi> > encode (Assignee { assigneeName = "foo" })
"{\"name\":\"foo\"}"