鉴于此数据:
data A1 = A1 | A2 | A3
如何为它创建实例?
instance ToJSON A1 where
toJSON = ???
instance FromJSON A1 where
parseJSON = ???
如果它是一个构造函数,我能够做到这一点,但我无法弄清楚如何使用多个不接受任何参数的方法来做到这一点。
更新: 对于每个构造函数,我都有这些错误:
my-app/src/Lib.hs:54:32:
No instance for (ToJSON a1) arising from a use of ‘.=’
The type variable ‘a1’ is ambiguous
Note: there are several potential instances:
instance ToJSON UUID -- Defined in ‘Data.UUID.Aeson’
instance ToJSON MyType -- Defined at src/Lib.hs:53:10
instance ToJSON MyType2 -- Defined at src/Lib.hs:70:10
In the expression: "tag" .= "A1"
In the first argument of ‘object’, namely ‘["tag" .= "A1"]’
In the expression: object ["tag" .= "A1"]
my-app/src/Lib.hs:54:35:
No instance for (Data.String.IsString a1)
arising from the literal ‘"A1"’
The type variable ‘a1’ is ambiguous
Note: there are several potential instances:
instance Data.String.IsString Value
-- Defined in ‘aeson-0.9.0.1:Data.Aeson.Types.Internal’
instance (a
~ bytestring-0.10.6.0:Data.ByteString.Internal.ByteString) =>
Data.String.IsString
(attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Internal.Parser a)
-- Defined in ‘attoparsec-0.13.0.1:Data.Attoparsec.ByteString.Char8’
instance Data.String.IsString
bytestring-0.10.6.0:Data.ByteString.Builder.Internal.Builder
-- Defined in ‘bytestring-0.10.6.0:Data.ByteString.Builder’
...plus 13 others
In the second argument of ‘(.=)’, namely ‘"A1"’
In the expression: "tag" .= "A1"
In the first argument of ‘object’, namely ‘["tag" .= "A1"]’
答案 0 :(得分:3)
toJSON
和parseJSON
函数各自参数,toJSON
最简单的可能是:
instance ToJSON A1 where
toJSON A1 = object ["tag" .= "A1"]
toJSON A2 = object ["tag" .= "A2"]
toJSON A3 = object ["tag" .= "A3"]
然后你只需要在parseJSON
中执行相反的操作:
instance FromJSON A1 where
parseJSON (Object o) = do
tag <- o .: "tag"
case tag of
"A1" -> return A1
"A2" -> return A2
"A3" -> return A3
_ -> mzero
这只是提取键#34;标记&#34;的值。然后对返回的Text执行模式匹配,以确定要使用的构造函数。
答案 1 :(得分:2)
编辑中显示的问题都与类型歧义有关,可以通过使用函数应用程序使类型可推断或添加类型注释来解决。
.=
的右侧是字符串文字,因此可能是String
或Text
或其他人 - 使用::Text
注释或者按照下面的操作进行注释并使用Text.pack . show
。.:
的结果是多态的,案例模式都是导致同样问题的字符串文字。在下面,我将:: Text
添加到tag
,从而消除了歧义。完整的代码:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Data.Aeson.Types
import Control.Monad
import Data.Text as Text
data A1 = A1 | A2 | A3
deriving (Eq, Ord, Show)
instance ToJSON A1 where
toJSON a = object ["tag" .= Text.pack (show a)]
instance FromJSON A1 where
parseJSON (Object o) = do
tag <- o .: "tag"
case (tag :: Text) of
"A1" -> return A1
"A2" -> return A2
"A3" -> return A3
_ -> mzero
parseJSON v = typeMismatch "A1" v