Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/lysxia/generic-data-surgery
Surgery for generic data types
https://github.com/lysxia/generic-data-surgery
generics haskell
Last synced: about 2 months ago
JSON representation
Surgery for generic data types
- Host: GitHub
- URL: https://github.com/lysxia/generic-data-surgery
- Owner: Lysxia
- License: mit
- Created: 2018-09-13T02:23:22.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2021-01-25T03:46:34.000Z (almost 4 years ago)
- Last Synced: 2024-04-26T01:31:03.931Z (8 months ago)
- Topics: generics, haskell
- Language: Haskell
- Size: 60.5 KB
- Stars: 23
- Watchers: 6
- Forks: 1
- Open Issues: 6
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
Awesome Lists containing this project
README
# Surgery for generic data types [![Hackage](https://img.shields.io/hackage/v/generic-data-surgery.svg)](https://hackage.haskell.org/package/generic-data-surgery) [![GitHub CI](https://github.com/Lysxia/generic-data-surgery/workflows/CI/badge.svg)](https://github.com/Lysxia/generic-data-surgery/actions)
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:
```haskell
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.
```haskell
instance FromJSON Foo where
parseJSON v = dor <- 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`.```haskell
instance ToJSON Foo where
toJSON f =
(genericToJSON defaultOptions . fromOR' . insertRField @"checksum" @3 . fmap toOR)
(checksum f, f)
```## See also
- [*Surgery for data types*](https://blog.poisson.chat/posts/2018-11-26-type-surgery.html),
introductory blog post with another example.- The [`examples/`](https://github.com/Lysxia/generic-data-surgery/tree/master/examples)
directory in the source repo.