generic-functor 0.0.1.0 → 0.0.1.1
raw patch · 3 files changed
+165/−2 lines, 3 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- CHANGELOG.md +4/−0
- README.md +159/−0
- generic-functor.cabal +2/−2
CHANGELOG.md view
@@ -1,3 +1,7 @@+## 0.0.1.1++* Include README+ ## 0.0.1.0 * Create generic-functor
+ README.md view
@@ -0,0 +1,159 @@+# Generic functors [](https://hackage.haskell.org/package/generic-functor) [](https://gitlab.com/lysxia/generic-functor/-/commits/main)+++Implementation of `Functor` instances and other functor-like structures+using `GHC.Generics`.++## Functors not over the last type parameter++The standard `Functor` class only applies to types that are functors over their+last type parameter. For example, in `Either e r`, `fmap` maps only `r`.++Using this library, `fmap`-like functions can be derived over any type+parameter of a `Generic` data type, all from the same definition `gsolomap`.++```haskell+{-# LANGUAGE DeriveGeneric #-}++import GHC.Generics (Generic)+import Generic.Functor (gsolomap)++data Result a r = Error a | Ok r -- Another name for Either+ deriving Generic++mapError :: (a -> b) -> Result a r -> Result b r+mapError = gsolomap++-- This one is fmap+mapOk :: (a -> b) -> Result e a -> Result e b+mapOk = gsolomap++mapBoth :: (a -> b) -> Result a a -> Result b b+mapBoth = gsolomap+```++`gsolomap` is **unsafe**. Misuse will break your program.+Read on for specifics.++### Usage++`gsolomap` should only be used to define **polymorphic** "`fmap`-like functions"+for `Generic` types.++The signature of `gsolomap` is:++```haskell+gsolomap :: (Generic x, Generic y, GSolomap a b x y) => (a -> b) -> (x -> y)+```++The types `x` and `y` must be specializations of the same user-defined `data`+type which is an instance of `Generic`, with some type parameters equal to `a`+or `b` respectively. At use sites of `gsolomap`, `a` and `b` must also be two+distinct universally quantified type variables, with no equality constraint+relating them with each other or any other type.++The guarantee is that `gsolomap` satisfies `gsolomap id = id`. Under the+condition that `a` and `b` are abstract, that equation uniquely determines the+implementation. (That uniqueness claim may be broken with GADTs and other+explicit uses of type equality constraints.)++In particular, `gsolomap` *must not* be specialized with types `a` and `b` that+are equal. A function defined using `gsolomap` is safe to specialize once+the `GSolomap` constraint has been discharged.++For instance the three functions above, `mapError`, `mapOk`, `mapBoth` are+sufficiently polymorphic.+They are each uniquely determined by their types and the equation `mapX id = id`.+(Without that equation, `mapBoth` has four implementations of the same type.)++## Compositions of functors++How many `fmap` do you need to map a function `a -> b` over+`(t, Maybe [Either Bool a])`?++You only need one `solomap`:++```haskell+type F t a = (t, Maybe [Either Bool a])++maps :: (a -> b) -> F t a -> F t b+maps = solomap+```++`solomap` can also see through bifunctors and there may be more than+one occurrence of the type parameter `a`.++```haskell+type F a = ([a], Either a ())++maps2 :: (a -> b) -> F a -> F b+maps2 = solomap+```++`solomap` is **unsafe**, subject to the same restrictions as `gsolomap`:+where `solomap` is used, the type of its first argument `(a -> b)` must refer+to two distinct universally quantified variables `a` and `b`.+Functions are safe to specialize only once the `Solomap` constraint is out of+their contexts.++```haskell+solomap :: Solomap a b x y => (a -> b) -> (x -> y)+```++## Deriving `Functor`++This library enables `DerivingVia` for the `Functor` class.++```haskell+{-# LANGUAGE DeriveGeneric, DerivingVia #-}++import GHC.Generics (Generic)+import Generic.Functor (DeriveFunctor(..))++data Twice a = Twice (Either a a)+ deriving Generic+ deriving Functor via (DeriveFunctor Twice)+```++Note that there is already built-in support for deriving `Functor` in GHC with the+`DeriveFunctor` extension instead. If that extension ever chokes on a type, this+library might have a chance at handling it. (Open an issue if it does not!)++The `Twice` example just above is not handled by the `DeriveFunctor` extension:++```haskell+{-# LANGUAGE DeriveFunctor #-}++data Twice a = Twice (Either a a) deriving Functor++{-+ error:+ • Can't make a derived instance of ‘Functor Twice’:+ Constructor ‘Twice’ must use the type variable only as the last argument of a data type+-}+```++The [*generic-data*][generic-data] library also includes a generic implementation of `Functor`,+but only for instances of `Generic1`, which applies to much more restricted shapes+of `data` than `Generic`.++---++## Internal module policy++The public API is `Generic.Functor`. Don't use `Generic.Functor.Internal`.++## Future work++- Bifunctors and variants with more than one function argument.+- Functors in arbitrary categories.++## Related links++- [*generic-data*][generic-data]++- [*Deriving Bifunctors with Generics*](https://kcsongor.github.io/generic-deriving-bifunctor/),+ blogpost by Csongor Kiss,+ describing the main idea for the implementation (using incoherent instances).++[generic-data]: https://hackage.haskell.org/package/generic-data
generic-functor.cabal view
@@ -1,6 +1,6 @@ cabal-version: >=1.10 name: generic-functor-version: 0.0.1.0+version: 0.0.1.1 synopsis: Deriving generalized functors with GHC.Generics description: Derive @fmap@, and other @fmap@-like functions where the@@ -16,7 +16,7 @@ copyright: Li-yao Xia 2020 category: Generics build-type: Simple-extra-source-files: CHANGELOG.md+extra-source-files: CHANGELOG.md, README.md library hs-source-dirs: src