Могу ли я использовать экземпляры ToJSON и FromJSON между Data.Aeson и Data.Yaml? - PullRequest
0 голосов
/ 26 апреля 2018

Data.Aeson и Data.Yaml - библиотеки для работы с JSON и YAML соответственно, которые имеют почти идентичные интерфейсы. Я написал экземпляры FromJSON и ToJSON «на основе Эзона» для некоторых из моих типов:

import Data.Aeson

data PropertyValue = Nested Microformat | Flat Text
    deriving (Generic, Show)

instance ToJSON PropertyValue where
    toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }

instance FromJSON PropertyValue where
    parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }

и в то время как Aeson использует эти экземпляры, Yaml, похоже, игнорирует их. (В частности, я считаю, что Yaml автоматически генерирует кодеры и декодеры благодаря тому, что мой тип получает Generic.) Я также попытался заставить экземпляры работать с Yaml, изменив код на

import Data.Aeson
import qualified Data.Yaml as Y

data PropertyValue = Nested Microformat | Flat Text
    deriving (Generic, Show)

instance ToJSON PropertyValue where
    toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }

instance FromJSON PropertyValue where
    parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }

instance Y.ToJSON PropertyValue where
    toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }

instance Y.FromJSON PropertyValue where
    parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }

но GHC пожаловался:

Duplicate instance declarations:
  instance ToJSON PropertyValue
    -- Defined at src/Microformats.hs:54:10
  instance ToJSON PropertyValue
    -- Defined at src/Microformats.hs:60:10

Разве невозможно определить экземпляры для двух разных классов, которые имеют одинаковые имена? Или ToJSON Yaml на самом деле тот же класс, что и Aeson как-то?

Более конкретно, возможно ли повторно использовать мои экземпляры ToJSON и FromJSON, чтобы избежать необходимости писать один и тот же код дважды? Если это не удастся, возможно ли по крайней мере написать экземпляры обеих библиотек '1020 * и FromJSON, не путая компилятор?

1 Ответ

0 голосов
/ 26 апреля 2018

Краткий ответ : классы типов ToJSONFromJSON) из Data.Aeson и Data.Yaml совпадают . Data.Yaml фактически выполняет только повторное импортирование из класса типов ToJSON Data.Aeson.

Если мы посмотрим на Data.Yaml исходный код :

#if (defined (ghcjs_HOST_OS))
module Data.Yaml {-# WARNING "GHCJS is not supported yet (will break at runtime once called)." #-}
#else
<b>module Data.Yaml</b>
#endif
    ( -- * Types
      Value (..)
    , Parser
    , Object
    , Array
    , ParseException(..)
    , prettyPrintParseException
    , YamlException (..)
    , YamlMark (..)
      -- * Constructors and accessors
    , object
    , array
    , (.=)
    , (.:)
    , (.:?)
    , (.!=)
      -- ** With helpers (since 0.8.23)
    , withObject
    , withText
    , withArray
    , withScientific
    , withBool
      -- * Parsing
    , parseMonad
    , parseEither
    , parseMaybe
      -- * Classes
    <b>, ToJSON (..)
    , FromJSON (..)</b>
      -- * Encoding/decoding
    , encode
    , encodeFile
    , decode
    , decodeFile
      -- ** Better error information
    , decodeEither
    , decodeEither'
    , decodeFileEither
      -- ** More control over decoding
    , decodeHelper
    ) where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative(())
#endif
import Control.Exception
<b>import Data.Aeson</b>
    ( Value (..), <b>ToJSON (..), FromJSON (..)</b>, object
    , (.=) , (.:) , (.:?) , (.!=)
    , Object, Array
    , withObject, withText, withArray, withScientific, withBool
    )
(...)

Таким образом, модуль экспортирует класс типов ToJSON, но это только результат ToJSON импорта Data.Aeson, следовательно, класс типов на самом деле тот же.

Таким образом, он повторно импортируется для удобства программиста (например, вам не нужно импортировать Data.Aeson только для реализации FromJOSN), но на самом деле вы все еще работаете с теми же типами, теми же классами типов и т. Д. Ведь ваши ToJSON и Y.ToJSON относятся к тому же классу типов.

Поскольку оба на самом деле одинаковы, вы не можете дважды создать один и тот же класс типов для одного и того же типа, но нам не нужно этого делать: если мы реализуем его для Data.Aeson (или Data.Yaml), то есть достаточно, так как ограничения класса типов, которые, например, записаны в Data.Yaml (или Data.Aeson), будут успешными. Как следствие, мы не можем (по крайней мере, без некоторых хитростей) реализовать ToJSON иначе для Data.Yaml, чем для Data.Aeson.

...