Json 使用Aeson';将产品类型编码为对象,而不是列表
在以下代码中,Json 使用Aeson';将产品类型编码为对象,而不是列表,json,haskell,aeson,Json,Haskell,Aeson,在以下代码中,encoded等于{“FooBar”:[{“Bar”:4},{“Baz”:2}} 所需的编码是{“FooBar”:{“Bar”:4,“Baz”:2} import Data.Aeson import Data.Aeson.Types data Foo = FooBar Bar Baz deriving Generic newtype Bar = Bar Integer deriving Generic newtype Baz = Baz
encoded
等于{“FooBar”:[{“Bar”:4},{“Baz”:2}}
所需的编码是{“FooBar”:{“Bar”:4,“Baz”:2}
import Data.Aeson
import Data.Aeson.Types
data Foo = FooBar Bar Baz deriving Generic
newtype Bar = Bar Integer deriving Generic
newtype Baz = Baz Integer deriving Generic
instance ToJSON Foo where
toJSON = genericToJSON options
instance ToJSON Bar where
toJSON = genericToJSON options
instance ToJSON Baz where
toJSON = genericToJSON options
options :: Options
options = defaultOptions { tagSingleConstructors = True,
sumEncoding = ObjectWithSingleField }
foo :: Foo
foo = FooBar (Bar 4) (Baz 2)
encoded = encode foo
也就是说,我希望产品类型的构造函数是键,它们的组件是对象。我已经能够非常接近tagSingleConstructors=True
和sumcodencing=ObjectWithSingleField
,但是Aeson将Bar
和Baz
放在一个列表中,而不是一个对象中
Options
中的其他修饰符似乎都不相关,但我可能遗漏了什么。使用genericToJSON
是否可以进行所需的编码?使用记录语法可以获得所需的结果。
在这种情况下,Aeson将值编码为对象。
但是,在这种情况下需要两组选项,一组用于FooBar
,另一组用于Foo
和Bar
:
data Foo = FooBar { bar:: Bar, baz :: Baz} deriving Generic
data Bar = Bar Integer deriving Generic
newtype Baz = Baz Integer deriving Generic
instance ToJSON Foo where
toJSON = genericToJSON options
instance ToJSON Bar where
toJSON = genericToJSON option_nested
instance ToJSON Baz where
toJSON = genericToJSON option_nested
options :: Options
options = defaultOptions { tagSingleConstructors = True,
sumEncoding = ObjectWithSingleField,
fieldLabelModifier = \s -> (toUpper . head) s : (tail s) }
option_nested :: Options
option_nested = defaultOptions { sumEncoding = UntaggedValue }
结果:
{“FooBar”:{“Baz”:2,“Bar”:4}}“
如果您有一个产品类型的总和类型会怎么样?我假设每个产品类型都可以是一个记录,但是如果在错误的产品类型上使用,您会有部分访问器,这将引发运行时错误。e.x.数据Foo=Bar{x::String}Baz{y::String}
x$Baz“Foo”“
不会抛出任何编译时警告/错误,但会导致运行时错误。当您有一个乘积和时,这就为不使用记录提供了有力的理由。