我可以在 Data.Aeson 和 Data.Yaml 之间重复使用 ToJSON 和 FromJSON 实例吗?
Can I reuse ToJSON and FromJSON instances between Data.Aeson and Data.Yaml?
Data.Aeson 和 Data.Yaml 分别是用于使用 JSON 和 YAML 的库,它们具有几乎相同的接口。我已经为我的某些类型编写了“基于 Aeson 的”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
是否不能为碰巧同名的两个不同 class 定义实例?或者 Yaml 的 ToJSON
实际上与 Aeson 的 相同 class?
更重要的是,是否可以重用我的 ToJSON
和 FromJSON
实例以避免必须将相同的代码编写两次?如果做不到这一点,是否至少可以在不混淆编译器的情况下编写两个库的 ToJSON
和 FromJSON
的实例?
简答:Data.Aeson
和Data.Yaml
的ToJSON
(和FromJSON
)类型类 相同。 Data.Yaml
实际上只对 Data.Aeson
.
的 ToJSON
类型类执行 reimport
如果我们看 Data.Yaml
source code:
#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
指的是 same 类型类。
由于两者实际上是一样的,所以不能为同一个类型实例化同一个类型类两次,但是我们不需要这样做:如果我们为Data.Aeson
(或Data.Yaml
),这就足够了,因为例如写在 Data.Yaml
(或 Data.Aeson
)中的类型类约束将会成功。结果是我们不能(至少不能没有一些技巧),以不同的方式实现 Data.Yaml
和 Data.Aeson
.
的 ToJSON
Data.Aeson 和 Data.Yaml 分别是用于使用 JSON 和 YAML 的库,它们具有几乎相同的接口。我已经为我的某些类型编写了“基于 Aeson 的”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
。)我试图通过将代码更改为
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
是否不能为碰巧同名的两个不同 class 定义实例?或者 Yaml 的 ToJSON
实际上与 Aeson 的 相同 class?
更重要的是,是否可以重用我的 ToJSON
和 FromJSON
实例以避免必须将相同的代码编写两次?如果做不到这一点,是否至少可以在不混淆编译器的情况下编写两个库的 ToJSON
和 FromJSON
的实例?
简答:Data.Aeson
和Data.Yaml
的ToJSON
(和FromJSON
)类型类 相同。 Data.Yaml
实际上只对 Data.Aeson
.
ToJSON
类型类执行 reimport
如果我们看 Data.Yaml
source code:
(...)#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
指的是 same 类型类。
由于两者实际上是一样的,所以不能为同一个类型实例化同一个类型类两次,但是我们不需要这样做:如果我们为Data.Aeson
(或Data.Yaml
),这就足够了,因为例如写在 Data.Yaml
(或 Data.Aeson
)中的类型类约束将会成功。结果是我们不能(至少不能没有一些技巧),以不同的方式实现 Data.Yaml
和 Data.Aeson
.
ToJSON