使用 Aeson 的 FromJSON 类型类可以轻松将 JSON 对象转换为 Haskell 中的类型。但是,Aeson 的默认行为是将 JSON 中的浮点数值转换为 Haskell 中的 Double 类型,而且不支持对数值进行四舍五入或者控制输出格式。
要解决这个问题,我们可以自定义一个解码器(Decoder),在解码 JSON 对象时加入对浮点数进行四舍五入的逻辑。
举个例子,假如我们有如下的 JSON 字符串:
{
"pi": 3.1415926535,
"e": 2.7182818284
}
我们想要将 pi 和 e 转换为 Haskell 中的 Rational 类型,并对 pi 进行两位小数的四舍五入。
代码示例如下:
{-# LANGUAGE OverloadedStrings #-}
import Data.Aeson
import Data.Scientific (toRealFloat)
import qualified Data.Text as T
import GHC.Real (Ratio((:%)))
data MyNumber = MyNumber Rational
instance FromJSON MyNumber where
parseJSON = withScientific "MyNumber" $ \s ->
let r = toRealFloat s :: Double
r' = fromRational $ toRational r
in return $ MyNumber $ fromRational $ toRational $ (fromInteger $ round $ r' * (10^n)) / (10^n)
where
n = 2 -- round to 2 decimal places, change as necessary
instance Show MyNumber where
show (MyNumber r) = T.unpack $ T.pack $ show $ fromRational r
jsonStr :: T.Text
jsonStr = "{\"pi\":3.1415926535,\"e\":2.7182818284}"
main :: IO ()
main = case eitherDecodeStrict jsonStr of
Left err -> putStrLn err
Right obj -> do
let myPi = obj :: Object -> Maybe MyNumber = \o -> do
p <- o
上一篇:Aeson合并对象编码