Haskell 让ToJSON使用Show实例

Haskell 让ToJSON使用Show实例,haskell,aeson,Haskell,Aeson,如果我的数据类型如下所示: data SumType = ABC | DEF deriving (Generic, ToJSON) data MyType = MyType {field1 :: String, field2 :: SumType} deriving (Generic, ToJSON) 上面生成的JSON看起来像:{“field1”:“blah”,“field2”:“ABC”} 实际上,MyType是一个相当复杂的类型,我想保持ToJSON的派生,但只想调整一个字段来使用sh

如果我的数据类型如下所示:

data SumType = ABC | DEF deriving (Generic, ToJSON)
data MyType = MyType {field1 :: String, field2 :: SumType} deriving (Generic, ToJSON) 
上面生成的JSON看起来像:
{“field1”:“blah”,“field2”:“ABC”}

实际上,
MyType
是一个相当复杂的类型,我想保持
ToJSON
的派生,但只想调整一个字段来使用show实例

 instance Show SumType where
   show ABC = "abc-blah"
   show DEF = "def-xyz" 
不幸的是,上面的
Show
实例没有被
ToJSON
获取(我不知道它是否应该被获取)。对于
SumType
,手动滚动
ToJSON
似乎不起作用,因为它需要一个键值对(可能还有其他方法吗?)。换句话说,JSON类似于:
{“field1”:“blah”,“field2”:{“field3”:“ABC”}
——我只想改变值字符串化的方式,而不是在那里创建新对象

关于如何在不为
MyType
手动创建
ToJSON
的情况下更改
SumType
的输出字符串,有什么建议吗?所以输出是
{“field1”:“blah”,“field2”:“abc blah”}


谢谢

我看不出为
SumType
定义
ToJSON
实例有什么问题。您可以通过以下方式执行此操作:

import Data.Aeson(ToJSON(toJSON), Value(String))
import Data.Text(pack)

instance ToJSON SumType where
    toJSON = String . pack . show
或者,如果您想对
ToJSON
使用其他字符串,而不是
Show

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson(ToJSON(toJSON), Value(String))

instance ToJSON SumType where
    toJSON ABC = String "ABC for JSON"
    toJSON DEF = String "DEF for JSON"
现在Haskell将把
SumType
编码为JSON字符串:

Prelude Data.Aeson> encode ABC
"\"ABC for JSON\""
Prelude Data.Aeson> encode DEF
"\"DEF for JSON\""
您可以对
FromJSON
执行相同的操作,将JSON字符串解析回
SumType
对象:

{-# LANGUAGE OverloadedStrings #-}

import Data.Aeson(FromJSON(parseJSON), withText)

instance FromJSON SumType where
    parseJSON = withText "SumType" f
        where f "ABC for JSON" = return ABC
              f "DEF for JSON" = return DEF
              f _ = fail "Can not understand what you say!"
如果我们随后解析回JSON字符串,我们会得到:

Prelude Data.Aeson> decode "\"ABC for JSON\"" :: Maybe SumType
Just ABC
Prelude Data.Aeson> decode "\"DEF for JSON\"" :: Maybe SumType
Just DEF
Prelude Data.Aeson> decode "\"other JSON string\"" :: Maybe SumType
Nothing
Prelude Data.Aeson> decode "{}" :: Maybe SumType
Nothing
因此,如果我们不解码遵循我们定义的模式之一的JSON字符串,解析将失败。如果我们不提供JSON字符串,例如一个空JSON对象,也会发生同样的情况

附加注释

  • 因为这里的
    SumType
    有两个值,所以您还可以使用JSON布尔值对这些值进行编码
  • 您还可以对不同的JSON对象进行编码。例如,您可以将JSON字符串用于
    ABC
    ,将整数用于
    DEF
    。 尽管我建议在有充分理由之前不要这样做 (例如,
    ABC
    仅携带字符串,而
    DEF
    仅携带一个字符串。) 整数)
  • 通常,编码越复杂,解码就越复杂

  • SumType
    创建
    ToJSON
    有什么问题?您可以使用
    Show-SumType
    @WillemVanOnsem中的定义,我认为
    ToJSON
    只接受
    对象。我没有意识到我可以只返回一个字符串。如果你把你的回答写在答案里,我可以接受。传递给
    with text
    “SumType”
    做什么?以其他方式解析时是否更改失败消息?这可能是一个很好的证明。