Home > OS >  Idiomatic Means to Rewrite Haskell Json Creating Library
Idiomatic Means to Rewrite Haskell Json Creating Library

Time:07-04

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.)

  • Related