我有一个类型MyType
,该类型由函子f
参数化。
我想用MyType Identity
代表数据的“我的观点”,用MyType Maybe
代表数据的更新的类型。
是否可以为ToJSON
编写aeson MyType
实例?我尝试使用ToJSON
类,但出现错误(请参阅文章底部)。
{-# LANGUAGE DeriveGeneric #-}
module Main where
import GHC.Generics
import Data.Aeson
data MyType f = MyType
{ age :: f Int
, name :: f String
} deriving(Generic)
instance ToJSON1 f => ToJSON (MyType f)
main :: IO ()
main = print . encode $ MyType (Just 1) (Just "hi")
如何为任意MyType f
获取f
的ToJSON实例?
Main.hs:12:10: error:
• Could not deduce (ToJSON (f String))
arising from a use of ‘aeson-1.2.4.0:Data.Aeson.Types.ToJSON.$dmtoJSON’
from the context: ToJSON1 f
bound by the instance declaration
at Main.hs:12:10-39
• In the expression:
aeson-1.2.4.0:Data.Aeson.Types.ToJSON.$dmtoJSON @MyType f
In an equation for ‘toJSON’:
toJSON = aeson-1.2.4.0:Data.Aeson.Types.ToJSON.$dmtoJSON @MyType f
In the instance declaration for ‘ToJSON (MyType f)’
|
12 | instance ToJSON1 f => ToJSON (MyType f)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Failed, no modules loaded.
答案 0 :(得分:2)
在利用Lifting
类的评论中使用我的想法,经过一番修补后,我得出了这个结论
{-# LANGUAGE DeriveGeneric
, FlexibleContexts
, MultiParamTypeClasses
, ScopedTypeVariables
, TypeApplications
, UndecidableInstances
#-}
module Main where
import GHC.Generics
import Data.Aeson
import Data.Constraint
import Data.Constraint.Lifting
data MyType f = MyType
{ age :: f Int
, name :: f String
} deriving(Generic)
instance (Lifting ToJSON f) => ToJSON (MyType f) where
toJSON mt
| Sub Dict <- lifting @ToJSON @f @Int
, Sub Dict <- lifting @ToJSON @f @String
= genericToJSON defaultOptions mt
instance Lifting ToJSON Maybe where
lifting = Sub Dict
main :: IO ()
main = print . encode $ MyType (Just 1) (Just "hi")
注意:
Dict
在约束(例如ToJSON Int
)和值之间来回转换。 Sub
只是约束约束的构造器。lifting @ToJSON @f @Int
是type application syntax。genericToJSON defaultOptions
的{{3}}来使用toJSON
。我们只需要首先使用lifting
手动将一些实例纳入范围。我希望这会有所帮助。