[hackage-flatparse]: https://hackage.haskell.org/package/flatparse
[hackage-megaparsec]: https://hackage.haskell.org/package/megaparsec
# generic-data-functions
A small Haskell library providing some funky generics that work over arbitrary
Haskell data types. We handle the sums of products representation; you only need
to pass a handful of definitions. Obtain simple, type-safe generic
serializers/reducers and parsers for almost zero effort.
Well, OK, so really this is a generic binary serialization library. It just so
happens that the generics look like `foldMap` and `traverse`.
## Really?
Kind of. We only handle *sequential concatenation*, being cleanly represented by
builtin type classes. Weirder cases like JSON parsing/serialization have more
going on, and aren't sensibly discussed generically. So you are probably only
going to use this with bytestrings and simple binary formats.
## Why?
It is 2023. There are a number of competing parsing and serialization Haskell
libraries, recently some notable high-performance ones. These are often fairly
experimental. Maybe you want some generics to benchmark some real-world use case
against popular libraries like binary and cereal. But maybe generics aren't
provided. Shucks.
That's a shame, because a binary/cereal-esque generic binary parser or
serializer doesn't have much work to do:
* traverse the generic sum-of-products tree of the given type left to right
* defer to the appropriate type class for base cases
Sum types necessitate a little more work. Otherwise, most such parsers and
serializers look fairly comparable to each other. Why are we rewriting this
stuff over and over again?
generic-data-functions provides *reusable generics* which have holes in for your
favorite parsers and serializers. Fill out a few definitions to receive a fresh
new generic instance for your own library, without all the boilerplate.
## Functions
### `foldMap` (L->R)
```haskell
foldMap :: (Foldable t, Monoid m) => (a -> m) -> t a -> m
```
The user provides the `a -> m` dictionary via a special type class instance.
Constructor fields are mapped and combined left-to-right. Sum representations
are handled by mappending the constructor via a user-supplied `String -> m`
first.
Useful for:
* simple binary serializers which just concatenate fields together
* reducing to a numeric value
### `traverse` (L->R)
```haskell
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
```
The user provides the `f a` dictionary via a special type class instance.
Constructor field actions are run left-to-right.
Sum representations are handled by running a constructor action first (thus
requiring `Monad f`).
Useful for:
* simple binary parsers which can parse generic `foldMap` output
## Notes
### Orphan instances
This library is designed to work with and around existing libraries and type
classes. Thus, you will likely be dealing in orphans. Instances, that is. That's
life, Jim.
### Funky generics
I have made some weird design choices in this library. Here are some rationales.
#### Handling badness on type & term levels
I don't like silently erroring on badly-configured generics usage, e.g. asking
for a function via generics for an empty data type. Originally, I made those
type error, and that was that. But it meant I would write the same instance over
and over again. And that requirement was hidden in a type class implementation.
Really, it'd be nice if I could put such requirements directly in the types of
the functions that have them.
I've done that. Now, on certain *representation errors*, e.g. you tried to use
non-sum generics on a sum type, we runtime error instead. However, there's a
separate layer for making *assertions about generic representation on the type
level*, the use of which is highly suggested.
Note that if you like to write wrappers over generic functions to fill in
certain bits of info, your job just got a lot uglier. Soz. Anything for type
safety my sweet.
## License
Provided under the MIT license. See `LICENSE` for license text.