I have parsed a large amount of json, manipulated some values and I'd like to write it back out. Aeson decodes numbers into scientific, but when it encodes it, by default, scientific shows numbers in scientific notation in many cases, and aeson does not offer any means that I can see to change that.
> decode "[\"asdf\", 1, 1.0, 1000000000.1, 0.01]" :: Maybe Value
Just (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
encode (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\"asdf\",1,1,1.0000000001e9,1.0e-2]"
> encode (Array [String "asdf", Number 1, Number 1.0, Number 1000000000.1, Number 0.01])
"[\"asdf\",1,1,1.0000000001e9,1.0e-2]"
How can I write out my Value with numbers in a more widely acceptable format that other languages can consume? Let's pretend I'm not concerned with precision loss or integer overflows. The scientific package has the means to format numbers in this manner, aeson just happened not to use it.
>formatScientific Fixed Nothing (0.01)
"0.01"
>formatScientific Fixed Nothing (1000000000.1)
"1000000000.1"
The pretty printer for Aeson (only since version 0.8, quite recent) has a configuration option that does exactly what you're asking:
Prelude> :m +Data.Aeson Data.Aeson.Encode.Pretty
Prelude Data.Aeson Data.Aeson.Encode.Pretty> encodePretty' (defConfig{confNumFormat=Decimal}) (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n \"asdf\",\n 1.0,\n 1.0,\n 1000000000.1,\n 0.01\n]"
Unfortunately, this pretty-printer now outputs the actual integral numbers as 1.0
instead of 1
, which I consider a much more severe problem than printing decimals in scientific notation (which really should be ok everywhere). This also happens with the default setting:
Prelude Data.Aeson Data.Aeson.Encode.Pretty> encodePretty (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n \"asdf\",\n 1.0,\n 1.0,\n 1.0000000001e9,\n 1.0e-2\n]"
Version 0.7.2 still printed integers without fractional part, like the normal aeson encode
does:
aeson-pretty-0.7.2:Data.Aeson.Encode.Pretty> encodePretty (Array [String "asdf",Number 1.0,Number 1.0,Number 1.0000000001e9,Number 1.0e-2])
"[\n \"asdf\",\n 1,\n 1,\n 1.0000000001e9,\n 1.0e-2\n]"
I think I'll file this as a bug report.
Note that there's also a Custom
NumberFormat
option, which gives you complete control about how numbers should appear.
I have looked for this functionality before myself; I believe at that time I was trying to interface with a Ruby program, and the standard Ruby JSON parser didn't support scientific notation. Unfortunately I believe aeson does not have a way to do it, so you will need to either patch aeson or write your own encoder.
There are further details on the aeson issue tracker. That issue additionally suggests using toEncoding
on a type other than Value
to achieve this, but it's not clear whether this is practical in your case or not.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With