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