I do not wish to be rude in asking this question; however, I have recently been attempting to learn Haskell and wish to understand the best practices of the language. I am currently reading about a library that parses a Haskell file and emits a parse tree as a json document. The contents of Main.hs appear repetitive and attempt to derive a json producer for every element of the parse tree. Do people commonly use code generators when writing Haskell programs? I would assume that computer created code would defeat the elegance of functional programming, or am I wrong? Would there be any idiomatic means of simplifying the following code?
// ~80 lines of the same statements have been elided
instance ToJSON l => ToJSON (FunDep l) where
toJSON (FunDep l n1 n2)
= object [pack "FunDep" .= [toJSON l, toJSON n1, toJSON n2]]
instance ToJSON l => ToJSON (GadtDecl l) where
toJSON (GadtDecl l n1 t2)
= object [pack "GadtDecl" .= [toJSON l, toJSON n1, toJSON t2]]
instance ToJSON l => ToJSON (FieldDecl l) where
toJSON (FieldDecl l n1 b2)
= object [pack "FieldDecl" .= [toJSON l, toJSON n1, toJSON b2]]
Given that all of the functions possess similar signatures, would it not be possible to create a function builder that returns the necessary parameters for each element of the parse tree? Or, could one at least store the necessary information in a csv file and retrieve it at runtime?
I am very enthusiastic regarding the continuation of my Haskell studies and do not wish to single out any particular repository.
CodePudding user response:
Generating code is normal, idiomatic, and used in exactly the file you pointed at. If you scroll up a few lines, you'll see:
-- FIXME: Waiting for https://github.com/bos/aeson/issues/206.
{-
-- ~15 lines of the same statements have been elided
$(deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''FunDep)
$(deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''GadtDecl)
$(deriveToJSON defaultOptions { sumEncoding = ObjectWithSingleField } ''FieldDecl)
-}
These lines are intended, at some point in the future, to expand to the ones you show; see the linked issue for more on why they don't currently.
(Aside: there is nothing stopping somebody from creating a deriveToJSONs
or something that takes a collection of type names instead of a single type name. They probably should do that, so that they could write
deriveToJSONs defaultOptions { sumEncoding = ObjectWithSingleField }
[''FunDep, ''GadtDecl, ''FieldDecl]
and just have a list with ~50 elements rather than 50 lines of deriving calls. Probably they just didn't think of it.)