MIT licensed by Li-yao Xia
Maintained by [email protected]
This version can be pinned in stack with:generic-data-surgery-0.3.0.0@sha256:b0bc01418e70fc89f891322b0598553c3ecebf76d281a17a879146d0ff376d10,1665

Module documentation for 0.3.0.0

Surgery for generic data types Hackage GitHub CI

Modify, add, or remove constructors and fields in generic types, to be used with generic implementations.

Example

Here is a simple record type equipped with a checksum function:

data Foo = Foo { x, y, z :: Int }
  deriving (Eq, Generic, Show)

checksum :: Foo -> Checksum

Let’s encode it as a JSON object with an extra "checksum" key, looking like this, where X, Y, Z are integers:

{ "x": X
, "y": Y
, "z": Z
, "checksum": X + Y + Z
}

We use genericParseJSON/genericToJSON to convert between JSON values and a generic 4-field record, and removeRField/insertRField to convert between that generic 4-field record and the 3-field Foo.

Remove field

When decoding, we check the checksum and then throw it away.

instance FromJSON Foo where
  parseJSON v = do

    r <- genericParseJSON defaultOptions v
    -- r: a generic 4-field record {x,y,z,checksum} (checksum at index 3).

    let (cs, f) = (fmap fromOR . removeRField @"checksum" @3 . toOR') r
    -- removeRField @"checksum" @3: split out the checksum field
    -- from the three other fields. (cs, f) :: (Checksum, Foo)

    if checksum f == cs then
      pure f
    else
      fail "Checksum failed"

Insert field

When encoding, we must compute the checksum to write it out. We put the checksum in a pair (checksum f, f) with the original record, and insertRField can then wrap it into a 4-field record passed into genericToJSON.

instance ToJSON Foo where
  toJSON f =
    (genericToJSON defaultOptions . fromOR' . insertRField @"checksum" @3 . fmap toOR)
      (checksum f, f)

See also

Changes

0.3.0.0

  • Make surgeries first-class at the type level (MajorSurgery)

0.2.1.0

  • Add toORLazy and fromORLazy, to clean up data types with strictness annotations. (Thanks to blmage.)

0.2.0.0

  • Compatibility with generic-data 0.4.0.0
  • Removed onData (moved to generic-data 0.4.0.0).

0.1.0.0

Initial version