2014-11-06 24 views
2

我正在为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. 也许我可以绕过编译器与模板哈斯克尔抱怨,但如何?
  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) 
    

使这一手的想法使我威金斯。如果我必须,我会的。

所以,现在我的问题是,如果没有其他更好的方法比我提出的方法,哪个是最好的行动方案?

+1

也许你可以在不同的模块,把它们写和不导入'name'功能。 – 2014-11-06 23:16:32

回答

7

最简单的方法是启用-XDisambiguateRecordFields扩展名。

+0

这样做,我只是把它们放在单独的模块中。 – 2014-11-07 00:45:19

6

如果DisambiguateRecordFields和/或保持独立模块中的记录适用于您,那很好。

如果没有,那么一个共同的方式来解决这个问题,在某种程度上前缀记录字段标签,消除歧义:

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

你仍然可以使用GHC泛型导出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\"}" 
相关问题