Revisiting JSON in Haskell
- Magnus Therning
I just received an email with some praise for my earlier post on JSON in Haskell–it’s always nice to receive some praise ;-) However, the sender also mentioned that the mLookup
function as coded there would blow up on incomplete JSON objects. That was by design, as a simplification, but the sender needed to deal with just that and asked if I had some more elegant solution than making every field in the data type a Maybe
.
As I said, it’s always nice to receive praise, so here’s one solution that came to mind as I was reading the email.
I should mention that it relies on there being a reasonable default value for each type of the fields, and that the default is the same for all fields sharing a type.
First off, define a type class for types with default values:
class Defaultable d where
def :: d
Then modify mLookup
so that it uses Defaultable
. I renamed it to mLookupAndReadJSON
:
= maybe def readJSON (lookup a as) mLookupAndReadJSON a as
Now we need to provide some instances of Defaultable
too. I limit this example to cover only GlossDef
, so only the following instances are required:
instance Defaultable [a] where
= []
def
instance Defaultable a => Defaultable (Result a) where
= Ok def def
Now it’s possible to decode incomplete JSON objects:
> decode "{ \"GlossSeeAlso\": [\"GML\", \"XML\"] }" :: Result GlossDef
ghciOk (GlossDef {glossDefPara = "", glossDefSeeAlso = ["GML","XML"]})
I’m sure there are other ways of achieving what the author of the email asked for. Please let me know of them in comments.