Revisiting JSON in Haskell
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:
mLookupAndReadJSON a as = maybe def readJSON (lookup 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 def = Ok def |
Now it’s possible to decode incomplete JSON objects:
ghci> decode "{ \"GlossSeeAlso\": [\"GML\", \"XML\"] }" :: Result GlossDef Ok (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.
You may be interested to see that the default class already exists in cmdargs: http://hackage.haskell.org/packages/archive/cmdargs/0.6.9/doc/html/System-Console-CmdArgs-Default.html
Neil,
It’s also coded up in
cmdargsis where I first came across this little trickData.Default, which can be found on Hackage.