# 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