如何应对Haskell名称空间?

时间:2012-12-12 21:30:27

标签: json haskell jira aeson

我正在编写data条记录以对JIRA JSON个对象进行编组。问题是,多个对象具有相同的名称/值对标签。例如:

(从curl返回并格式化)

{"expand":"schema,names"
,"startAt":0
,"maxResults":2
,"total":74
,"issues":[
           {"expand":"editmeta,renderedFields,transitions,changelog,operations"
           ,"id":"183614"
           ,"self":"https://10.64.16.44/rest/api/latest/issue/183614"
           ,"key":"BNAP-339"
           ,"fields":{"versions":[
                                  {"self":"https://10.64.16.44/rest/api/2/version/28240"  
                                  ,"id":"28240"
                                  ,"name":"2012-12-07"
                                  ,"archived":false
                                  ,"released":false
                                  }
                                 ]
                     ,"status":{"self":"https://10.64.16.44/rest/api/2/status/1"
                               ,"description":"The issue is open and ready for the assignee to start work on it."
                               ,"iconUrl":"https://10.64.16.44/images/icons/status_open.gif"
                               ,"name":"Open"
                               ,"id":"1"
                               }
                     ,"description":"Do Re Mi Fa"
                     ,"resolution":null
                     }
           }
          ]

当我构造有问题的相应Haskell data记录时,我得到:

data Issue = Issue {expand :: String
                   ,id :: String
                   ,self :: String
                   ,key :: String
                   ,fields :: Fields
                   } deriving Generic


data Version = Version {self :: String
                       ,id :: String
                       ,name :: String
                       ,archived :: Bool
                       ,released :: Bool
                       } deriving Generic

和'id'和'self'会发生冲突。它发生在我身上我只需更改记录中的名称并使用手动创建的FromJSON实例进行修复即可解决此问题。 任何替代解决方案都是受欢迎的。

2 个答案:

答案 0 :(得分:10)

我在协议缓冲区中通过将IssueVersion之类的内容放在同一层次结构中的单独文件中来解决此问题。

Haskell只使用单独的模块来控制名称空间,因此这是正统的解决方案。

非常有趣:使用类型类来定义可用名称:

class Has'self a b | a -> bwhere
   get'self :: a -> b
   set'self :: b -> a -> b

instance Has'self Issue String where ...
instance Has'self Version String where ....
编辑:以下评论提醒我提供更详细的建议。不要使用Has'self喜欢的解决方案 - 那些已经走过那条道路报告它变得难看。我可以保证单独模块的路径。

PS:也许你可以在你的领域使用lens库!

答案 1 :(得分:3)

另一个应该起作用的替代方法是使用包含不同记录的单个数据类型。例如,以下数据类型能够表示您的值而不会发生字段冲突:

import Prelude hiding (id)

data JIRA = JIRA
  { expand :: String
  , startAt :: Int
  , maxResults :: Int
  , total :: Int
  , issues :: [JIRA]
  } | Issue 
  { expand :: String
  , id :: Int
  , self :: String
  , key :: String
  , fields :: JIRA
  } | Field
  { versions :: [JIRA]
  , status :: JIRA
  , description :: String
  , resolution :: Maybe String
  } | Version
  { self :: String
  , id :: Int
  , name :: String
  , archived :: Bool
  , released :: Bool
  } | Status
  { self :: String
  , description :: String
  , iconUrl :: String
  , name :: String
  , id :: Int
  }


yourExample = JIRA
  { expand = "schema, names"
  , startAt = 0
  , maxResults = 2
  , total = 74
  , issues = [ Issue
               { expand = "editmeta, etc..."
               , id = 12345
               , self = "https://xyz"
               , key = "BLAH"
               , fields = Field
                          { versions = [ Version
                                          { self = "https://foobar"
                                          , id = 1234
                                          , name = "quux"
                                          , archived = False
                                          , released = False
                                          }
                                       ]
                          , status = Status
                                     { self = "https://etc"
                                     , description = "issue"
                                     , iconUrl = "https://iconurl"
                                     , name = "open"
                                     , id = 1
                                     }
                          , description = "another description"
                          , resolution = Nothing
                          }
                 }
               ]
  }