red-black-record 1.0.0.0 → 1.0.0.1
raw patch · 2 files changed
+193/−3 lines, 2 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- README.md +185/−0
- red-black-record.cabal +8/−3
+ README.md view
@@ -0,0 +1,185 @@+# red-black-record + +## What's this? + +A library that provides extensible records and variants, both indexed by a +type-level [red-black](https://en.wikipedia.org/wiki/Red%E2%80%93black_tree) +tree that maps `Symbol` keys to `Type`s. The keys correspond to fields names in +records, and to branch names in variants. Many record functions have their +variant mirror-images and viceversa. + +Each value type in a field or branch comes wrapped in a type constructor of +kind `Type -> Type`. Typically, it will be an [identity +functor](http://hackage.haskell.org/package/sop-core-0.4.0.0/docs/Data-SOP.html#t:I), +but it can also be `Maybe` or some other `Applicative` for parsing, validation +and so on. + +If we forget about the keys and only keep the values, records are isomorphic to +[n-ary unlabeled +products](http://hackage.haskell.org/package/sop-core-0.4.0.0/docs/Data-SOP.html#t:NP), +and variants are isomorphic to [n-ary unlabeled +sums](http://hackage.haskell.org/package/sop-core-0.4.0.0/docs/Data-SOP.html#t:NS). +The [sop-core](http://hackage.haskell.org/package/sop-core) library provides +such unlabeled types, along with a rich API for manipulating them. Instead of +reinventing the wheel, red-black-record defines conversion functions to +facilitate working in the "unlabeled" world and then coming back to records and +variants. + +There is another world towards which bridges must be built: the everyday +Haskell world of conventional records and sums. In fact, one of the motivations +of extensible records and variants is to serve as "generalized" versions of +vanilla data types. Advanced use cases can rely on these generalized versions, +thereby avoiding intrusive changes to the original types. red-black-record +provides conversion typeclasses with default implementations by way of +[`GHC.Generic`](http://hackage.haskell.org/package/base-4.12.0.0/docs/GHC-Generics.html). + +For examples on how to use the library, check the haddocks for the +`Data.RBR.Examples` module. + +## FAQ + +### What extensions do I need to use this library? + +- `DataKinds` + +- `TypeApplications` + + To be able to specify field and branch names. + +- `FlexibleContexts` + +- `TypeFamilies` + +- `DeriveGeneric ` + + For interfacing with normal records. + +- `PartialTypeSignatures` + +### My type signatures are getting big and scary because of those type-level trees. What to do? + +The +[`-XPartialTypeSignatures`](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html?#extension-PartialTypeSignatures) +extension can help with that, in combination with the +[-Wno-partial-type-signatures](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/using-warnings.html#ghc-flag--Wpartial-type-signatures) +GHC flag that disables the warning message emitted when the underscore is +encountered in a signature. + +The flag can be set globally in the +[ghc-options](https://www.haskell.org/cabal/users-guide/developing-packages.html?#pkg-field-ghc-options) +section of the .cabal file, and also for particular modules with the +[OPTIONS_GHC](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html?highlight=options_ghc#options-ghc-pragma) +file-header pragma. + +### The `Show` instance for record doesn't show any field names. + +The field names exist only at the type level. Also, the `Show` instance uses +n-ary products and sums from +[sop-core](http://hackage.haskell.org/package/sop-core), which do not have +field labels. + +For fancier output, use the "pretty-show" functions instead. + +### Working with two records, I'm getting errors about incompatible types even as both records have the exact same fields. + +Alas, the order of insertion in the type-level tree matters :( Different +insertion orders can produce structurally different trees, even as they encode +the same symbol-to-type map. + +As a workaround, one can use the `-Subset` functions to convert between +equivalent structures. + +### I can't insert into a record when a field with the same name but different type already exists. Why not simply overwrite it? + +That limitation was intentional, because allowing it would make impossible to +implement of `widen` for `Variant`. When/if key deletion gets implemented +type-level tree, one solution would be to explicitly delete the field and then +insert it again. + +### The library doesn't use Proxy and relies on type application instead. But what’s the order of the type parameters? + +For typeclass methods, it's the order in which the type variables appear in the +typeclass declaration. + +For standalone functions, it’s the order in which the type variables appear in +the `forall`. + +### What's the deal with all those -I suffixed versions of functions? + +This library aims to provide +[HKD](http://reasonablypolymorphic.com/blog/higher-kinded-data/)-like +functionality by wrapping all the fields of a record in a type constructor. + +But sometimes we are working with "pure" records without effects, and we just +want to get and set a field's value. In that case, the type constructor that +wraps each field will be an identity functor `I` (from +[sop-core](http://hackage.haskell.org/package/sop-core)). The -I suffixed +functions wrap and unwrap the field's value on behalf of the user. + +### What's the deal with all those -Subset suffixed versions of functions? + +These functions target multiple fields or branches at the same time. They can +be used to build lawful lenses and prisms over fragmenst of a structure. + +They can also be used to convert between type-level trees that have the same +entries but different structure. + +### I want a version of "match" that when it fails returns a variant with the unmatched cases. + +That isn't implemented (yet). It would require key deletion on the type-level +tree. + +## Inspirations + +- The code for the red-black tree has been lifted from ["Persistent Red Black + Trees in Haskell"](https://abhiroop.github.io/Haskell-Red-Black-Tree/). + +- Besides depending on sop-core, I have copied and adapted code from it. In + particular the `KeysValuessAll` typeclass is a version of the `All` typeclass + from sop-core. + +- [Surgery for data + types](https://blog.poisson.chat/posts/2018-11-26-type-surgery.html). + [reddit](https://www.reddit.com/r/haskell/comments/a0gi4z/surgery_for_data_types/). + +## Alternatives + +- [generics-sop](http://hackage.haskell.org/package/generics-sop) and + [records-sop](http://hackage.haskell.org/package/records-sop). Like + red-black-record, both of these libraries build upon sop-core. They are in + fact written by the same author of sop-core. generics-sop can provide + sum-of-products representations of any datatype with a Generic instance + (red-black-record is more limited, it only converts types that fit the named + record or variant mold—so no types with anonymous fields for example). + + If you don't need to explicitly target *individual* fields in the generic + representation, you'll be better off using generics-sop instead of + red-black-record. + + On top of generics-sop, records-sop provides named field accessors and record + subtyping based on a type-level list of fields (unlike the type-level tree + used by red-black-record). It doesn't seem to provide variants. + +- [superrecord](http://hackage.haskell.org/package/superrecord). This library + provides very efficient field access at runtime because the fields are backed + internally by an array. Uses a *sorted* type-level list of fields, to avoid + the problems of multiple orderings of the same fields. + +- [vinyl](http://hackage.haskell.org/package/vinyl). One of the oldest and more + fully-featured extensible records libraries. Uses a type level list of + fields. The fields' values are wrapped in a type constructor, like in + sop-core. The records seem to use an auxiliary sum type that serves as a + "code" for the fields. + +- [HTree](https://github.com/i-am-tom/learn-me-a-haskell#htree). Another + implementation of extensible records using type-level red-black trees. + +- [megarecord](https://github.com/jvanbruegge/Megarecord). Seems to be a + proof-of-concept for a future [row polymorphism + extension](https://github.com/ghc-proposals/ghc-proposals/pull/180) for + Haskell. + +- [generic-data-surgery](https://hackage.haskell.org/package/generic-data-surgery) + +- [Coxswain](https://ghc.haskell.org/trac/ghc/wiki/Plugins/TypeChecker/RowTypes/Coxswain) +
red-black-record.cabal view
@@ -1,6 +1,6 @@-cabal-version: >=2.0 +cabal-version: 2.0 name: red-black-record -version: 1.0.0.0 +version: 1.0.0.1 synopsis: Extensible records and variants indexed by a type-level Red-Black tree. description: A library that provides extensible records and variants, @@ -22,8 +22,13 @@ author: Daniel Diaz maintainer: diaz_carrete@yahoo.com category: Data -extra-source-files: CHANGELOG.md +extra-source-files: CHANGELOG.md, + README.md build-type: Simple + +source-repository head + type: git + location: https://github.com/danidiaz/red-black-record.git library exposed-modules: Data.RBR