Кодировка Aeson Data.Map.Strict.Map с пользовательским типом ключа приводит к массиву массивов вместо объекта - PullRequest
1 голос
/ 09 марта 2019

У меня проблемы с тем, чтобы Aeson выплевывал объекты, когда я использую пользовательские типы в качестве ключей.Позвольте мне продемонстрировать:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

import Data.Aeson

import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B

import GHC.Generics

data LOL = A | B | C deriving (Eq, Ord, Generic, ToJSONKey, ToJSON)
main = do
    B.putStrLn $ encode $ M.fromList [(A,"b")]
    B.putStrLn $ encode $ M.fromList [("A","b")]

В одном случае я получаю массив массивов, а в другом - обычный объект:

$ ./tojsonkey 
[["A","b"]]
{"A":"b"}

Есть идеи?

1 Ответ

1 голос
/ 09 марта 2019

Взгляните на документы для ToJSONKey. По сути, метод toJSONKey :: ToJSONKeyFunction a обрабатывает два случая:

  1. когда вы можете превратить ключ непосредственно в текст типа
  2. когда лучшее, что вы можете сделать, это превратить ключ в какой-то общий JSON

Для первого из них aeson будет использовать правильный объект JSON. Для последнего он возвращается к вложенным массивам.

Так почему же в вашем случае выбирается второй вариант? Потому что вы получаете ToJSONKey, а реализация по умолчанию выбирает второй более общий вариант. Вы можете обойти эту проблему, вручную внедрив ToJSONKey LOL:

{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}

import Data.Aeson
import Data.Aeson.Types

import qualified Data.Text as T
import qualified Data.Map.Strict as M
import qualified Data.ByteString.Lazy.Char8 as B

import GHC.Generics

data LOL = A | B | C deriving (Eq, Ord, Show, Generic, ToJSON)
instance ToJSONKey LOL where
  toJSONKey = toJSONKeyText (T.pack . show)

main = do
    B.putStrLn $ encode $ M.fromList [(A,"b")]
    B.putStrLn $ encode $ M.fromList [("A","b")]

Это должно дать вам

$ ./tojsonkey 
{"A":"b"}
{"A":"b"}
...