Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell Aeson解码可以是字符串或int的JSON对象_Haskell_Aeson - Fatal编程技术网

Haskell Aeson解码可以是字符串或int的JSON对象

Haskell Aeson解码可以是字符串或int的JSON对象,haskell,aeson,Haskell,Aeson,我正在处理来自REST服务器的一些复杂格式的JSON响应。为了解码它们,我有两种数据类型来处理不同的嵌套对象。例如: ... Other types ... data Profile = Profile { fields :: [KVPair] } deriving (Show) instance FromJSON Profile where parseJSON (Object v) = Profile <$> v .: "Fields" parseJS

我正在处理来自REST服务器的一些复杂格式的JSON响应。为了解码它们,我有两种数据类型来处理不同的嵌套对象。例如:

... Other types ...

data Profile =
  Profile { fields :: [KVPair]
  } deriving (Show)

instance FromJSON Profile where
  parseJSON (Object v) =
    Profile <$> v .: "Fields" 
  parseJSON _ = mzero

data KVPair =
  KVPair { key :: Int
         , value :: String
  } deriving (Show)

instance FromJSON KVPair where
  parseJSON (Object v) =
    KVPair <$> v .: "Key"
           <*> v .: "Value" 
  parseJSON _ = mzero

现在我想我可以在我的值解码中添加另一个sum类型,它由
String
Int
组成,但我更愿意避免为此添加一个全新的类型Aeson是否有一种简单的方法来处理这种情况?

您只需使用Aeson值类型来处理具有可以是任何JSON值的字段的对象。

有两种简单的修复方法。一种是简单地写

data KVPair = KVPair { key :: Int, value :: Value }
所有其他代码保持不变。消费者需要检查
,看看它是字符串y还是数字y

可能更好的方法是简单地提供两个可选的解析器,它们都可以转换为您想要的格式。例如,保持您的
KVPair
定义不变,可以编写

showInt :: Int -> String
showInt = show

instance FromJSON KVPair where
    parseJSON (Object v)
        =   KVPair
        <$> v .: "Key"
        <*> (v .: "Value" <|> (showInt <$> v .: "Value"))

对象已经是HashMap(在Aeson中)。只需查找所需的值。如果这还不够,您可以将JSON解析为任意字符串。如果我正确理解您的可选解析方法,它只会将整数值强制为字符串类型,对吗?所以“Value”:3会转换成类似KVPair{Value=“3”}的东西,对吗?@jkeuhlen完全正确,尽管“强制”在Haskell中有一个特定的含义,但在这里不适用--“转换”或“漂亮打印”更接近正确。
showInt :: Int -> String
showInt = show

instance FromJSON KVPair where
    parseJSON (Object v)
        =   KVPair
        <$> v .: "Key"
        <*> (v .: "Value" <|> (showInt <$> v .: "Value"))
data KVPair = KVPair { key :: Int, value :: Either String Int }

instance FromJSON KVPair where
    parseJSON (Object v)
        =   KVPair
        <$> v .: "Key"
        <*> (   (Left  <$> v .: "Value")
            <|> (Right <$> v .: "Value")
            )