Aeson:派生结构的一些(但不是全部)字段
Aeson: derive some (but not all) fields of a struct
我有一个大型结构,我需要它成为 FromJSON 的一个实例,以便我可以将我的 json 数据解析到其中。
我想自动派生,但单个字段需要 "special care",因为它是 json 中的一个对象,我希望它是我的结构中的值数组。如果不编写重复所有字段的庞大 FromJson 实现,我该如何做到这一点?
示例json:
{"myobject": {"one": 1, "two": 2}, ...many_more_fields...}
示例结构:
data MyStruct = MyStruct {
myobject :: [Int],
...many_more_fields,...
} deriving (Generic)
如何优雅地执行此操作?
你应该为你的专业创建一个newtype
:
newtype MySpecialType = MySpecialType [Int]
instance FromJSON MySpecialType where ....
data MyStruct = MyStruct {
myobject:: MySpecialType,
...
}
现在 MyStruct
的实例完全正常,可以以正常方式移交给模板 Haskell。
为了避免在整个代码库中携带来自 的新类型,您还可以按如下方式概括您的类型,使 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 about "type surgery",适用于此类问题,可以保持原类型不变。
The generic-data-surgery library可以派生出与上面MyStruct_ MySpecialType
结构相同Generic
结构的泛型,供aeson的genericParseJSON
使用。手术 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
我有一个大型结构,我需要它成为 FromJSON 的一个实例,以便我可以将我的 json 数据解析到其中。
我想自动派生,但单个字段需要 "special care",因为它是 json 中的一个对象,我希望它是我的结构中的值数组。如果不编写重复所有字段的庞大 FromJson 实现,我该如何做到这一点?
示例json:
{"myobject": {"one": 1, "two": 2}, ...many_more_fields...}
示例结构:
data MyStruct = MyStruct {
myobject :: [Int],
...many_more_fields,...
} deriving (Generic)
如何优雅地执行此操作?
你应该为你的专业创建一个newtype
:
newtype MySpecialType = MySpecialType [Int]
instance FromJSON MySpecialType where ....
data MyStruct = MyStruct {
myobject:: MySpecialType,
...
}
现在 MyStruct
的实例完全正常,可以以正常方式移交给模板 Haskell。
为了避免在整个代码库中携带来自 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 about "type surgery",适用于此类问题,可以保持原类型不变。
The generic-data-surgery library可以派生出与上面MyStruct_ MySpecialType
结构相同Generic
结构的泛型,供aeson的genericParseJSON
使用。手术 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