aeson icon indicating copy to clipboard operation
aeson copied to clipboard

Consider general `toJSON` `toEncoding` implementation

Open dylex opened this issue 4 years ago • 0 comments

I get fairly tired of implementing both toJSON and toEncoding for ToJSON, but it seems to me there's a solution, by extending the KeyValue concept a bit:

-- So we can use Monoid KeyValue instances
instance KeyValue [Pair] where
  k .= v = [k .= v]

class (KeyValue p, Monoid p) => JSONRep p r | r -> p, p -> r where
  repJSON :: ToJSON a => a -> r
  repPair :: Text -> r -> p
  repObject :: p -> r
  repList :: [r] -> r

instance JSONRep [Pair] Value where
  repJSON = toJSON
  repPair = (.=)
  repObject = object
  repList = toJSON

instance JSONRep Series Encoding where
  repJSON = toEncoding
  repPair = pair
  repObject = pairs
  repList = list id

(The names and specifics are just for example -- I'm sure there are better options and variations of repList etc.)

This would allow a single implementation for many things:

myThingRep :: JSONRep p r => MyThing -> r
myThingRep t = repObject
  $  "thing" J..= thing t
  <> "values" `repPair` repList (map valueRep $ values t)

instance ToJSON MyThing where
  toJSON = myThingRep
  toEncoding = myThingRep

Thoughts? Improvements? (I'd prefer to do this with a TypeFamily for p but not sure how to get the constraints right.)

dylex avatar Nov 01 '20 03:11 dylex