Aeson: получить некоторые (но не все) поля структуры - PullRequest
0 голосов
/ 23 ноября 2018

У меня есть большая структура, которая должна быть экземпляром FromJSON, чтобы я мог анализировать в нем свои данные json.

Я хотел бы получить данные автоматически, но отдельное поле требует "особой заботы"в том смысле, что это объект в json, и я хочу, чтобы он был массивом значений в моей структуре.Как я могу сделать это без написания огромной реализации FromJson, повторяющей все поля?

Пример json:

{"myobject": {"one": 1, "two": 2}, ...many_more_fields...}

Пример структуры:

data MyStruct = MyStruct {
  myobject :: [Int],
  ...many_more_fields,...
} deriving (Generic)

Как мне сделатьэто элегантно?

Ответы [ 2 ]

0 голосов
/ 26 ноября 2018

Чтобы избежать переноса нового типа из очень хороший ответ Пола Джонсона по всей кодовой базе, вы также можете обобщить свой тип следующим образом, сделав тип myobject параметром:

data MyStruct_ intList = MyStruct {
  myobject :: intlist,
  ...
} deriving (Functor, Generic)

type MyStruct = MyStruct [Int]

instance FromJSON MyStruct where
  parseJSON = (fmap . fmap) (\(MySpecialType i) -> i)
            . genericParseJSON defaultOptions

genericParseJSON выше получает экземпляр с MyStruct MySpecialType, а затем поле разворачивается через fmap (отмечая MyStruct_ это Functor)


Я также только что написал blogpost о «типовой хирургии» , примененный к такого рода проблеме, чтобы вы могли сохранить исходный тип неизмененным.

Библиотека операций с общими данными может получитьуниверсальный тип с той же структурой Generic, что и MyStruct_ MySpecialType выше, для использования в genericParseJSON aeson.Затем операция modifyRField применяет функцию \(MySpecialType i) -> i к полю myobject, в результате чего получается MyStruct.

import Generic.Data.Surgery (fromOR, toOR', modifyRField)

-- The original type
data MyStruct = MyStruct {
  myobject :: [Int],
  ...
} deriving (Generic)

instance FromJSON MyStruct where
  parseJSON = fmap (fromOR . modifyRField @"myobject" (\(MySpecialType i) -> i) . toOR')
            . genericParseJSON defaultOptions
.
0 голосов
/ 23 ноября 2018

Вы должны создать newtype для своего специального поля:

newtype MySpecialType = MySpecialType [Int]

instance FromJSON MySpecialType where ....

data MyStruct = MyStruct {
      myobject:: MySpecialType,
      ...
   }

Теперь экземпляр для MyStruct становится полностью регулярным и может быть передан в Template Haskell обычным способом.

...