You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Aeson在解码JSON时区分负零与非负零?

Aeson解码JSON负零丢失符号位的原因与解决方法

Haskell原生支持区分浮点数的正负零:

ghci> (isNegativeZero (0 :: Float), isNegativeZero (-0 :: Float))
(False,True)

JSON语法层面也允许0和-0作为合法数值,但使用Aeson解码-0时,会丢失负零的符号位:

ghci> isNegativeZero <$> eitherDecode "-0"
Right False

原因

Aeson默认的浮点数解码逻辑,是将JSON的数值字符串转换为Haskell的Float/Double类型。底层解析过程中,会把"-0"直接解析为数值0.0,没有保留IEEE 754浮点数负零的符号位信息——常规的数值转换逻辑默认将正负零视为等价,因此最终得到的浮点数是正零。

解决方法

要在解码时区分正负零,需要自定义JSON解码器,先读取JSON的原始数值字符串,判断是否为"-0",再手动构造负零:

import Data.Aeson
import Data.Aeson.Types
import Data.Float (negativeZero)
import Numeric (formatScientific, Generic)

instance FromJSON Float where
  parseJSON = withScientific "Float" $ \sci ->
    case formatScientific Generic Nothing sci of
      "-0" -> pure negativeZero
      numStr -> case reads numStr of
        [(f, "")] -> pure f
        _ -> fail $ "无法解析为Float: " ++ numStr

这个自定义实例会先把科学计数法表示的数值转回字符串形式,若字符串是"-0",就返回Haskell的负零值;其他情况按常规方式解析为浮点数,这样就能保留负零的符号位了。

内容的提问来源于stack exchange,提问作者Janus Troelsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 12:00:54