diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,32 @@
+## New in 1.0
+
+* Breaking change: all instances now need to specify the variance of all type
+  parameters.
+* Breaking change: instances of the form `NFunctor (f a)` are no longer
+  allowed. Instead, write `NFunctor f` and use `NonvariantT` to indicate that
+  `a` cannot be mapped.
+* `NFunctor` is now even more general: in addition to generalizing `Functor`,
+  `Bifunctor`, `Trifunctor`, etc., it now also generalizes `Contravariant`,
+  `Invariant`, and `Profunctor`!
+* Introducing new infix operators corresponding to each variance. `(<#>)` is
+  still used for covariant type parameters, so after updating the instances,
+  all the call sites which were using the 0.1 API should still work. `(>#<)` is
+  used for contravariant type parameters, `(<#>/>#<)` is used for invariant
+  type parameters, which can be mapped given both a covariant and a
+  contravariant function, and `(👻#👻)` is used for phantom type parameters.
+* Introducing the `(-#-)` operator, which can be used instead of any other
+  operator in order to leave the corresponding type parameter untouched.
+* Introducing support for mapping over type parameters of kind `* -> *` using
+  natural transformations. The corresponding infix operators have two hashes:
+  the covariant operator is `(<##>)`, the contravariant operator is `(>##<)`,
+  etc.
+* Introducing the `VarianceTransformer` typeclass, via which you can add
+  support for other variances and other kinds.
+* It is no longer needed (nor allowed) to write both an `NFunctor Either`
+  instance and an `NFunctor (Either a)` instance corresponding to `Either`'s
+  `Bifunctor` and `Functor` instances. Instead, the `NFunctor (Either a)`
+  instance is derived from the `NFunctor Either` instance.
+
 ## New in 0.1.0.0
 
 * Initial release of the `NFunctor` typeclass
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,14 +1,160 @@
-# N-ary Functors
+# N-ary Functors [![Hackage](https://img.shields.io/hackage/v/n-ary-functor.svg)](https://hackage.haskell.org/package/n-ary-functor) [![Build Status](https://secure.travis-ci.org/gelisam/n-ary-functor.png?branch=master)](https://travis-ci.org/gelisam/n-ary-functor)
 
+## Using existing instances
+
 [`Functor`](https://hackage.haskell.org/package/base-4.10.1.0/docs/Prelude.html#t:Functor) and [`Bifunctor`](https://hackage.haskell.org/package/base-4.10.1.0/docs/Data-Bifunctor.html#t:Bifunctor) are both in `base`, but what about `Trifunctor`? `Quadrifunctor`? There must be a better solution than creating an infinite tower of typeclasses. Here's the API I managed to implement:
 
-    > nmap <#> (+1) <#> (+2) $ (0, 0)
-    (1,2)
+```haskell
+> nmap <#> (+1) <#> (+2) $ (0, 0)
+(1,2)
 
-    > nmap <#> (+1) <#> (+2) <#> (+3) $ (0, 0, 0)
-    (1,2,3)
+> nmap <#> (+1) <#> (+2) <#> (+3) $ (0, 0, 0)
+(1,2,3)
 
-    > nmap <#> (+1) <#> (+2) <#> (+3) <#> (+4) $ (0, 0, 0, 0)
-    (1,2,3,4)
+> nmap <#> (+1) <#> (+2) <#> (+3) <#> (+4) $ (0, 0, 0, 0)
+(1,2,3,4)
+```
 
-For more details, see the [documentation](https://hackage.haskell.org/package/n-ary-functor-0.1.0.0/docs/NAryFunctor.html) and the [blog post](http://gelisam.blogspot.ca/2017/12/n-ary-functors.html).
+What about [`Contravariant`](https://www.stackage.org/haddock/lts-14.20/base-4.12.0.0/Data-Functor-Contravariant.html#t:Contravariant) and [`Profunctor`](https://www.stackage.org/haddock/lts-14.20/profunctors-5.3/Data-Profunctor.html#t:Profunctor)? No need to define `Bicontravariant` nor `Noobfunctor`, the `NFunctor` typeclass supports contravariant type-parameters too!
+
+```haskell
+> let intToInt       =                            succ
+> let intToString    = nmap            <#> show $ succ
+> let stringToString = nmap >#< length <#> show $ succ
+> intToInt 3
+4
+> intToString 3
+"4"
+> stringToString "foo"
+"4"
+```
+
+As the examples above demonstrate, n-ary-functor has an equivalent for both the `Functor ((->) a)` instance and the `Profunctor (->)` instance. Even better: when writing your own instance, you only need to define an `NFunctor (->)` instance, and the `NFunctor ((->) a)` instance will be derived for you. `NFunctor ((->) a b)` too, but that's less useful since that `nmap` is just the identity function.
+
+That's not all! Consider a type like `StateT s m a`. The last type parameter is covariant, but what about the first two? Well, `s -> m (a, s)` has both positive and negative occurences of `s`, so you need both an `s -> t` and a `t -> s` function in order to turn a `StateT s m a` into a `StateT t m a`. And what about `m`? You need a natural transformation `forall a. m a -> n a`. Yes, n-ary-functor supports these too!
+
+```haskell
+> let stateIntIdentityInt    = ((`div` 2) <$> get) >>= lift . Identity
+> let stateStringMaybeString = nmap
+                       <#>/>#< (flip replicate '.', length)  -- (s -> t, t -> s)
+                          <##> NT (Just . runIdentity)       -- NT (forall a. m a -> n a)
+                           <#> show                          -- a -> b
+                             $ stateIntIdentityInt
+> runStateT stateIntIdentityInt 4
+Identity (2,4)
+> runStateT stateStringMaybeString "four"
+Just ("2","....")
+```
+
+Notice how even in such a complicated case, no type annotations are needed, as n-ary-functor is written with type inference in mind.
+
+
+## Defining your own instance
+
+When defining an instance of `NFunctor`, you need to specify the variance of every type parameter using a "variance stack" ending with `(->)`. Here is the instance for `(,,)`, whose three type parameters are covariant:
+
+```haskell
+instance NFunctor (,,) where
+  type VarianceStack (,,) = CovariantT (CovariantT (CovariantT (->)))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> \(x1,x2,x3)
+      -> (f1 x1, f2 x2, f3 x3)
+```
+
+Its `nmap` then receives 3 functions, which it applies to the 3 components of the 3-tuple.
+
+Here is a more complicated instance, that of `StateT`:
+
+```haskell
+instance NFunctor StateT where
+  type VarianceStack StateT = InvariantT (Covariant1T (CovariantT (->)))
+  nmap = InvariantT  $ \(f1, f1')
+      -> Covariant1T $ \f2
+      -> CovariantT  $ \f3
+      -> \body
+      -> StateT $ \s'
+      -> fmap (f3 *** f1) $ unwrapNT f2 $ runStateT body $ f1' s'
+```
+
+The `s` type parameter is "invariant", a standard but confusing name which does _not_ mean that the parameter cannot vary, but rather that we need both an `s -> t` and a `t -> s`. The `m` parameter is covariant, but for a type parameter of kind `* -> *`, so we follow the [convention](http://hackage.haskell.org/package/base-4.11.1.0/docs/Data-Functor-Classes.html) and add a `1` to the name of the variance transformer, hence `Covariant1T`.
+
+
+## Defining your own variance transformer
+
+We've seen plenty of strange variances already and n-ary-functor provides stranger ones still (can you guess what the `👻#👻` operator does?), but if your type parameters vary in an even more unusual way, you can define your own variance transformer. Here's what the definition of `CovariantT` looks like:
+
+```haskell
+newtype CovariantT to f g = CovariantT
+  { (<#>) :: forall a b
+           . (a -> b)
+          -> f a `to` g b
+  }
+```
+
+One thing which is unusual in that newtype definition is that instead of naming the eliminator `unCovariantT`, we give it the infix name `(<#>)`. See [this blog post](http://gelisam.blogspot.com/2017/12/n-ary-functors.html#ergonomics) for more details on that aspect.
+
+Let's look at the type wrapped by the newtype. `to` is the rest of the variance stack, so in the simplest case, `to` is just `(->)`, in which case the wrapped type is `(a -> b) -> f a -> g b`, which is really close to the type of `fmap`. The reason we produce a `g b` instead of an `f b` is because previous type parameters might already be mapped; for example, in `nmap <#> show <#> show $ (0, 0)`, the overall transformation has type `(,) Int Int -> (,) String String`, so from the point of view of the second `(<#>)`, `f` is `(,) Int` and `g` is `(,) String`.
+
+One last thing is that variance transformers must implement the `VarianceTransformer` typeclass. It simply ensures that there exists a neutral argument, in this case `id`, which doesn't change the type parameter at all.
+
+```haskell
+instance VarianceTransformer CovariantT a where
+  t -#- () = t <#> id
+```
+
+
+### Flavor example
+
+A concrete situation in which you'd want to define your own variance transformer is if you have a DataKind type parameter which corresponds to a number of other types via type families.
+
+```haskell
+import qualified Data.ByteString      as Strict
+import qualified Data.ByteString.Lazy as Lazy
+import qualified Data.Text            as Strict
+import qualified Data.Text.Lazy       as Lazy
+
+data Flavor
+  = Strict
+  | Lazy
+
+type family ByteString (flavor :: Flavor) :: * where
+  ByteString 'Lazy   = Lazy.ByteString
+  ByteString 'Strict = Strict.ByteString
+
+type family Text (flavor :: Flavor) :: * where
+  Text 'Lazy   = Lazy.Text
+  Text 'Strict = Strict.Text
+
+data File (flavor :: Flavor) = File
+  { name     :: Text flavor
+  , size     :: Int
+  , contents :: ByteString flavor
+  }
+```
+
+In order to convert a `File 'Lazy` to a `File 'Strict`, we need to map both the underlying `Text 'Lazy` to a `Text 'Strict` and the underlying `ByteString 'Lazy` to a `ByteString 'Strict`. So those are exactly the two functions our custom variance transformer will ask for:
+
+```haskell
+newtype FlavorvariantT to f g = FlavorvariantT
+  { (😋#😋) :: forall flavor1 flavor2
+           . ( ByteString flavor1 -> ByteString flavor2
+             , Text       flavor1 -> Text       flavor2
+             )
+          -> f flavor1 `to` g flavor2
+  }
+
+instance VarianceTransformer FlavorvariantT a where
+  t -#- () = t 😋#😋 (id, id)
+```
+
+We can now implement our `NFunctor File` instance by specifying that its `flavor` type parameter is flavorvariant.
+
+```haskell
+instance NFunctor File where
+  type VarianceStack File = FlavorvariantT (->)
+  nmap = FlavorvariantT $ \(f, g)
+      -> \(File n s c)
+      -> File (g n) s (f c)
+```
diff --git a/Setup.hs b/Setup.hs
--- a/Setup.hs
+++ b/Setup.hs
@@ -1,2 +1,6 @@
-import Distribution.Simple
-main = defaultMain
+module Main where
+
+import Distribution.Extra.Doctest (defaultMainWithDoctests)
+
+main :: IO ()
+main = defaultMainWithDoctests "doctests"
diff --git a/n-ary-functor.cabal b/n-ary-functor.cabal
--- a/n-ary-functor.cabal
+++ b/n-ary-functor.cabal
@@ -1,27 +1,47 @@
 name:                n-ary-functor
-version:             0.1.0.0
+version:             1.0
 synopsis:            An n-ary version of Functor
-description:         A single typeclass for Functor, Bifunctor, Trifunctor, etc.
+description:         A single typeclass for Functor, Bifunctor, Profunctor, etc.
 homepage:            https://github.com/gelisam/n-ary-functor
 license:             PublicDomain
 author:              Samuel Gélineau
 maintainer:          gelisam+github@gmail.com
 category:            Data
-build-type:          Simple
+build-type:          Custom
 cabal-version:       >=1.10
 extra-source-files:  README.md
                    , CHANGELOG.md
 
+source-repository head
+   type: git
+   location: https://github.com/gelisam/n-ary-functor
+
+source-repository this
+   type: git
+   location: https://github.com/gelisam/n-ary-functor
+   tag: v1.0
+
+custom-setup
+ setup-depends:
+   base >= 4 && <5,
+   Cabal,
+   cabal-doctest >= 1 && <1.1
+
 library
+  ghc-options:         -Wall
   exposed-modules:     NAryFunctor
-  build-depends:       base >=4.9 && <4.11
+  build-depends:       base >=4.9 && <5
+                     , natural-transformation >= 0.4
+                     , transformers -any
   hs-source-dirs:      src
   default-language:    Haskell2010
 
 test-suite doctests
   default-language:   Haskell2010
   type:               exitcode-stdio-1.0
-  ghc-options:        -threaded
+  ghc-options:        -Wall -threaded
   main-is:            doctests.hs
-  build-depends:      base >4 && <5, doctest, doctest-discover
-  HS-Source-Dirs:     test
+  build-depends:      base >4 && <5
+                    , doctest
+                    , n-ary-functor
+  hs-source-dirs:     test
diff --git a/src/NAryFunctor.hs b/src/NAryFunctor.hs
--- a/src/NAryFunctor.hs
+++ b/src/NAryFunctor.hs
@@ -1,90 +1,469 @@
-{-# LANGUAGE RankNTypes, TypeFamilies, TypeFamilyDependencies, TypeInType #-}
+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, PolyKinds, RankNTypes, TypeFamilies, TypeOperators, UndecidableInstances, UnicodeSyntax #-}
 module NAryFunctor
   ( NFunctor(..)
-
-  -- * Internals
-  , NMap1(..), NMap
+  , VarianceTransformer(..)
+  , CovariantT(..),     Covariant1T(..)
+  , ContravariantT(..), Contravariant1T(..)
+  , InvariantT(..),     Invariant1T(..)
+  , NonvariantT(..)
+  , PhantomvariantT(..)
   ) where
 
+import Control.Arrow
+import Control.Monad.Trans.Reader
+import Control.Monad.Trans.State
+import Control.Monad.Trans.Writer
+import Control.Natural
 import Data.Bifunctor
+import Data.Functor.Const
 import Data.Functor.Identity
-import Data.Kind (Type)
 
+-- $setup
+-- >>> import Control.Monad.Trans.Class
+-- >>> let (<&>) = flip (<$>)
 
+
 -- |
--- A generalization of 'Functor', 'Bifunctor', 'Trifunctor', etc.
+-- A generalization of 'Functor', 'Bifunctor', 'Contravariant', 'Profunctor', etc.
 --
--- Example usage:
+-- * @(NFunctor f, VarianceStack f ~ CovariantT (->)@ is equivalent to @Functor f@.
+-- * @(NFunctor f, VarianceStack f ~ CovariantT (CovariantT (->))@ is equivalent to
+--   @Bifunctor f@.
+-- * @(NFunctor f, VarianceStack f ~ ContravariantT (->)@ is equivalent to
+--   @Contravariant f@.
+-- * @(NFunctor f, VarianceStack f ~ InvariantT (->)@ is equivalent to
+--   @Invariant f@.
+-- * @(NFunctor f, VarianceStack f ~ ContravariantT (CovariantT (->))@ is equivalent
+--   to @Profunctor f@.
 --
--- >>> nmap <#> (+1) $ Identity (0::Int)
--- Identity 1
+-- The associated type 'VarianceStack' specifies the variance of all the type
+-- parameters using a stack of 'VarianceTransformer's ending with @(->)@.
 --
--- >>> nmap <#> (+1) <#> (+2) $ (0::Int, 0::Int)
--- (1,2)
+-- Example instance:
 --
--- >>> nmap <#> (+1) <#> (+2) <#> (+3) $ (0::Int, 0::Int, 0::Int)
--- (1,2,3)
+-- > instance NFunctor (,,) where
+-- >   type VarianceStack (,,) = CovariantT (CovariantT (CovariantT (->)))
+-- >   nmap = CovariantT $ \f1
+-- >       -> CovariantT $ \f2
+-- >       -> CovariantT $ \f3
+-- >       -> \(x1,x2,x3)
+-- >       -> (f1 x1, f2 x2, f3 x3)
 --
+-- Note that it is /not/ possible to write an instance for a partially-applied
+-- type; for example, it is not possible to write an @NFunctor ((,,) a)@
+-- instance corresponding to the @Functor ((,,) a)@ instance. Instead, the
+-- @NFunctor ((,,) a)@ and @NFunctor ((,,) a b)@ instances are derived from the
+-- above instance.
+--
 -- Laws:
 --
--- > nmap <#> id <#> ... <#> id = id
--- > (nmap <#> f1 <#> ... <#> fN) . (nmap <#> g1 <#> ... <#> gN) = nmap <#> (f1 . g1) <#> ... <#> (fN . gN)
+-- > nmap <#>     id       = nmap -#- () = id
+-- > nmap     >#< id       = nmap -#- () = id
+-- > nmap <#>/>#< (id, id) = nmap -#- () = id
+-- > ...
 --
--- Example instance:
+-- > nmap -#- () -#- () <#> f =
+-- > nmap        -#- () <#> f =
+-- > nmap               <#> f
 --
--- > instance NFunctor (,,) where
--- >   nmap = NMap1 $ \f1
--- >       -> NMap1 $ \f2
--- >       -> NMap1 $ \f3
--- >       -> \(x1,x2,x3)
--- >       -> (f1 x1, f2 x2, f3 x3)
+-- > (nmap <#> f1 <#> f2) . (nmap <#> g1 <#> g2) = nmap <#> (f1 . g1) <#> (f2 . g2)
+-- > (nmap >#< f1 >#< f2) . (nmap >#< g1 >#< g2) = nmap >#< (g1 . f1) >#< (g2 . f2)
+-- > ...
 class NFunctor (f :: k) where
-  nmap :: NMap k f f
+  type VarianceStack f :: k -> k -> *
+  nmap :: VarianceStack f f f
 
 
 -- |
--- Types like 'Either' which have both a 'Functor' and a 'Bifunctor' instance
--- can have more than one 'NFunctor' instance. Those instances all define the
--- same method, 'nmap', but they return a value of a different type, which is
--- how the correct 'NFunctor' instance is picked:
---
--- > nmap :: NMap1 Type (Either a) (Either a)    -- Functor
--- > nmap :: NMap1 (Type -> Type) Either Either  -- Bifunctor
+-- This library uses a stack of 'VarianceTransformer's to indicate the variance
+-- of each type parameter. Each transformer in the stack specifies the variance
+-- of one type parameter, and wraps an inner stack specifying the variance of
+-- the remaining type parameters, until we reach @(->)@, the base of the stack.
 --
--- This 'NMap1' is unwrapped by using '<#>' to pass in the next input function.
--- In the case of @NMap1 (Type -> Type)@, the result after passing this input
--- function is another 'NMap1', which needs to be unwrapped using a second
--- '<#>'. The end result is that the 'Functor' behaviour is obtained by using a
--- single '<#>', and the 'Bifunctor' behaviour is obtained by using two.
+-- Each 'VarianceTransformer' is eliminated by an infix function, such as
+-- @(\<\#\>)@. This function takes a stack on the left, and its second argument
+-- has whatever type is necessary in order to map over the corresponding
+-- type parameter; for covariant type parameters, it will be a function of type
+-- @(a -> b)@, for contravariant type parameters, it will be a function of
+-- type @(b -> a)@, for invariant type parameters, it will be a pair of
+-- functions @(a -> b, b -> a)@, etc.
 --
--- >>> nmap <#> (+1) $ Right (0::Int)
--- Right 1
--- >>> nmap <#> (+1) <#> (+2) $ Left (0::Int)
--- Left 1
-newtype NMap1 k (f :: Type -> k) (f' :: Type -> k) = NMap1
-  { (<#>) :: forall a b. (a -> b) -> NMap k (f a) (f' b)
+-- The @(-\#-)@ method witnesses the fact that regardless of the variance of a
+-- given type parameter, there is always an identity-like argument which can be
+-- passed as that second argument which will cause that type parameter to be
+-- left unchanged. It takes a stack on the left, and its second argument is
+-- simply @()@.
+class VarianceTransformer (t :: (k -> k -> *)
+                             -> (k1 -> k) -> (k1 -> k) -> *)
+                          (a :: k1)
+                          where
+  (-#-) :: t inner f g -> () -> inner (f a) (g a)
+
+
+newtype CovariantT to f f' = CovariantT
+  { (<#>) :: forall a a'
+           . (a -> a')
+          -> f a `to` f' a'
   }
 
-type family NMap k = (r :: k -> k -> Type) | r -> k where
-  NMap Type        = (->)
-  NMap (Type -> k) = NMap1 k
+instance VarianceTransformer CovariantT a where
+  t -#- () = t <#> id
 
 
--- | For kind @* -> *@ ('Functor'), 'nmap' must be @NMap1 fmap@.
---
--- >>> nmap <#> (+1) $ Right (0::Int)
--- Right 1
-instance NFunctor (Either a) where
-  nmap = NMap1 fmap
+newtype ContravariantT to f f' = ContravariantT
+  { (>#<) :: forall a a'
+           . (a' -> a)
+          -> f a `to` f' a'
+  }
 
--- | For kind @* -> * -> *@ ('Bifunctor'), 'nmap' must be @NMap1 $ \f1 -> NMap1 $ \f2 -> bimap f1 f2@.
+instance VarianceTransformer ContravariantT a where
+  t -#- () = t >#< id
+
+
+newtype InvariantT to f f' = InvariantT
+  { (<#>/>#<) :: forall a a'
+               . (a -> a', a' -> a)
+              -> f a `to` f' a'
+  }
+
+instance VarianceTransformer InvariantT a where
+  t -#- () = t <#>/>#< (id, id)
+
+
+-- |
+-- If you can't figure out how to map over a particular type parameter, use
+-- this variance and we'll leave it alone. The corresponding infix operator is
+-- @(-\#-)@.
+newtype NonvariantT to f f' = NonvariantT
+  { unNonvariant :: forall a a'. (a ~ a')
+                 => f a `to` f' a'
+  }
+
+instance VarianceTransformer NonvariantT a where
+  t -#- () = unNonvariant t
+
+
+-- |
+-- Phantom type parameters can be changed to any other type, no @a -> b@
+-- function needed, so we only ask for a @()@. Use @(-\#-)@ in the common case
+-- in which you don't want to change the phantom type, and @(👻#👻)@ in the
+-- rare case in which you do want to change it.
+newtype PhantomvariantT to f f' = PhantomvariantT
+  { (👻#👻) :: forall a a'
+             . ()
+            -> f a `to` f' a'
+  }
+
+instance VarianceTransformer PhantomvariantT a where
+  t -#- () = t 👻#👻 ()
+
+
+
+newtype Covariant1T to f f' = Covariant1T
+  { (<##>) :: forall m m'. (Functor m, Functor m')
+           => m :~> m'
+           -> f m `to` f' m'
+  }
+
+instance Functor m
+      => VarianceTransformer Covariant1T m where
+  t -#- () = t <##> NT id
+
+
+newtype Contravariant1T to f f' = Contravariant1T
+  { (>##<) :: forall m m'. (Functor m, Functor m')
+           => m' :~> m
+           -> f m `to` f' m'
+  }
+
+instance Functor m
+      => VarianceTransformer Contravariant1T m where
+  t -#- () = t >##< NT id
+
+
+newtype Invariant1T to f f' = Invariant1T
+  { (<##>/>##<) :: forall m m'. (Functor m, Functor m')
+                => (m :~> m', m' :~> m)
+                -> f m `to` f' m'
+  }
+
+instance Functor m
+      => VarianceTransformer Invariant1T m where
+  t -#- () = t <##>/>##< (NT id, NT id)
+
+
+
+-- |
+-- A bold instance! We should be suspicious of any instance for @f a@, because
+-- it is likely to overlap with other instances. For instance, what if we want
+-- to define an @NFunctor ((->) a)@ instance corresponding to the @Functor ((->) a)@
+-- instance?
 --
+-- I claim that you will never have to write such an instance; it will always
+-- be possible to write the @NFunctor (->)@ instance instead, and to have the
+-- @NFunctor ((->) a)@ derived from the @NFunctor (->)@ instance via this bold
+-- instance. If you really can't find a way to map over a type parameter, use
+-- 'NonvariantT' to skip over it.
+instance ( NFunctor f
+         , VarianceStack f ~ t inner
+         , VarianceTransformer t a
+         )
+      => NFunctor (f a) where
+  --type VarianceStack (f a) = inner
+  type VarianceStack (f a) = VarianceStack'Tail (VarianceStack f)
+  nmap = nmap -#- ()
+
+-- We can't write @type VarianceStack (f a) = inner@, ghc complains that 'inner' is not
+-- in scope, so we instead have to write this type family which extracts 'inner'
+-- from @VarianceStack f@.
+type family VarianceStack'Tail f where
+  VarianceStack'Tail (t inner) = inner
+
+
+
+-- Instances
+
+-- $
+-- >>> nmap          <#> (+2) $ Right (0::Int)
+-- Right 2
 -- >>> nmap <#> (+1) <#> (+2) $ Left (0::Int)
 -- Left 1
+--
+-- >>> nmap          -#- ()   $ Right (0::Int)
+-- Right 0
+-- >>> nmap <#> (+1) -#- ()   $ Left (0::Int)
+-- Left 1
+-- >>> nmap -#- ()   <#> (+2) $ Right (0::Int)
+-- Right 2
+-- >>> nmap -#- ()   -#- ()   $ Left (0::Int)
+-- Left 0
 instance NFunctor Either where
-  nmap = NMap1 $ \f1 -> NMap1 $ \f2 -> bimap f1 f2
+  type VarianceStack Either = CovariantT (CovariantT (->))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> bimap f1 f2
 
+-- $
+-- >>> let intToInt       =                            succ
+-- >>> let intToString    = nmap            <#> show $ succ
+-- >>> let stringToString = nmap >#< length <#> show $ succ
+-- >>> intToInt 3
+-- 4
+-- >>> intToString 3
+-- "4"
+-- >>> stringToString "foo"
+-- "4"
+--
+-- >>> let intToInt    = nmap            -#- ()   $ succ
+-- >>> let stringToInt = nmap >#< length -#- ()   $ succ
+-- >>> let intToString = nmap -#- ()     <#> show $ succ
+-- >>> let intToInt'   = nmap -#- ()     -#- ()   $ succ
+-- >>> intToInt 3
+-- 4
+-- >>> stringToInt "foo"
+-- 4
+-- >>> intToString 3
+-- "4"
+-- >>> intToInt' 3
+-- 4
+instance NFunctor (->) where
+  type VarianceStack (->) = ContravariantT (CovariantT (->))
+  nmap = ContravariantT $ \f1'
+      -> CovariantT $ \f2
+      -> \g
+      -> f2 . g . f1'
 
+-- $
+-- >>> let readerIntIdentityInt    = ((`div` 2) <$> ask) >>= lift . Identity
+-- >>> let readerIntIdentityString = nmap                                         <#> show $ readerIntIdentityInt
+-- >>> let readerIntMaybeString    = nmap            <##> NT (Just . runIdentity) <#> show $ readerIntIdentityInt
+-- >>> let readerStringMaybeString = nmap >#< length <##> NT (Just . runIdentity) <#> show $ readerIntIdentityInt
+-- >>> runReaderT readerIntIdentityInt 4
+-- Identity 2
+-- >>> runReaderT readerIntIdentityString 4
+-- Identity "2"
+-- >>> runReaderT readerIntMaybeString 4
+-- Just "2"
+-- >>> runReaderT readerStringMaybeString "four"
+-- Just "2"
+--
+-- >>> let readerIntIdentityInt'      = nmap                                         -#- ()   $ readerIntIdentityInt
+-- >>> let readerIntMaybeInt          = nmap            <##> NT (Just . runIdentity) -#- ()   $ readerIntIdentityInt
+-- >>> let readerIntIdentityString    = nmap            -#-  ()                      <#> show $ readerIntIdentityInt
+-- >>> let readerIntIdentityInt''     = nmap            -#-  ()                      -#- ()   $ readerIntIdentityInt
+-- >>> let readerStringMaybeInt       = nmap >#< length <##> NT (Just . runIdentity) -#- ()   $ readerIntIdentityInt
+-- >>> let readerStringIdentityString = nmap >#< length -#-  ()                      <#> show $ readerIntIdentityInt
+-- >>> let readerStringIdentityInt    = nmap >#< length -#-  ()                      -#- ()   $ readerIntIdentityInt
+-- >>> let readerIntMaybeString       = nmap -#- ()     <##> NT (Just . runIdentity) <#> show $ readerIntIdentityInt
+-- >>> let readerIntMaybeInt'         = nmap -#- ()     <##> NT (Just . runIdentity) -#- ()   $ readerIntIdentityInt
+-- >>> let readerIntIdentityString'   = nmap -#- ()     -#-  ()                      <#> show $ readerIntIdentityInt
+-- >>> let readerIntIdentityInt'''    = nmap -#- ()     -#-  ()                      -#- ()   $ readerIntIdentityInt
+-- >>> runReaderT readerIntIdentityInt' 4
+-- Identity 2
+-- >>> runReaderT readerIntMaybeInt 4
+-- Just 2
+-- >>> runReaderT readerIntIdentityString 4
+-- Identity "2"
+-- >>> runReaderT readerIntIdentityInt'' 4
+-- Identity 2
+-- >>> runReaderT readerStringMaybeInt "four"
+-- Just 2
+-- >>> runReaderT readerStringIdentityString "four"
+-- Identity "2"
+-- >>> runReaderT readerStringIdentityInt "four"
+-- Identity 2
+-- >>> runReaderT readerIntMaybeString 4
+-- Just "2"
+-- >>> runReaderT readerIntMaybeInt' 4
+-- Just 2
+-- >>> runReaderT readerIntIdentityString' 4
+-- Identity "2"
+-- >>> runReaderT readerIntIdentityInt''' 4
+-- Identity 2
+instance NFunctor (ReaderT :: * -> (* -> *) -> * -> *) where
+  type VarianceStack ReaderT = ContravariantT (Covariant1T (CovariantT (->)))
+  nmap = ContravariantT $ \f1'
+      -> Covariant1T $ \f2
+      -> CovariantT $ \f3
+      -> \body
+      -> ReaderT $ \r'
+      -> fmap f3 $ unwrapNT f2 $ runReaderT body $ f1' r'
+
+-- $
+-- >>> let stateIntIdentityInt    = ((`div` 2) <$> get) >>= lift . Identity
+-- >>> let stateIntIdentityString = nmap                                                                   <#> show $ stateIntIdentityInt
+-- >>> let stateIntMaybeString    = nmap                                      <##> NT (Just . runIdentity) <#> show $ stateIntIdentityInt
+-- >>> let stateStringMaybeString = nmap <#>/>#< (flip replicate '.', length) <##> NT (Just . runIdentity) <#> show $ stateIntIdentityInt
+-- >>> runStateT stateIntIdentityInt 4
+-- Identity (2,4)
+-- >>> runStateT stateIntIdentityString 4
+-- Identity ("2",4)
+-- >>> runStateT stateIntMaybeString 4
+-- Just ("2",4)
+-- >>> runStateT stateStringMaybeString "four"
+-- Just ("2","....")
+--
+-- >>> let stateIntIdentityInt'      = nmap                                                                           -#- ()   $ stateIntIdentityInt
+-- >>> let stateIntMaybeInt          = nmap                                              <##> NT (Just . runIdentity) -#- ()   $ stateIntIdentityInt
+-- >>> let stateIntIdentityString    = nmap                                              -#-  ()                      <#> show $ stateIntIdentityInt
+-- >>> let stateIntIdentityInt''     = nmap                                              -#-  ()                      -#- ()   $ stateIntIdentityInt
+-- >>> let stateStringMaybeInt       = nmap <#>/>#< (flip replicate '.', length) <##> NT (Just . runIdentity) -#- ()   $ stateIntIdentityInt
+-- >>> let stateStringIdentityString = nmap <#>/>#< (flip replicate '.', length) -#-  ()                      <#> show $ stateIntIdentityInt
+-- >>> let stateStringIdentityInt    = nmap <#>/>#< (flip replicate '.', length) -#-  ()                      -#- ()   $ stateIntIdentityInt
+-- >>> let stateIntMaybeString       = nmap -#-     ()                           <##> NT (Just . runIdentity) <#> show $ stateIntIdentityInt
+-- >>> let stateIntMaybeInt'         = nmap -#-     ()                           <##> NT (Just . runIdentity) -#- ()   $ stateIntIdentityInt
+-- >>> let stateIntIdentityString'   = nmap -#-     ()                           -#-  ()                      <#> show $ stateIntIdentityInt
+-- >>> let stateIntIdentityInt'''    = nmap -#-     ()                           -#-  ()                      -#- ()   $ stateIntIdentityInt
+-- >>> runStateT stateIntIdentityInt' 4
+-- Identity (2,4)
+-- >>> runStateT stateIntMaybeInt 4
+-- Just (2,4)
+-- >>> runStateT stateIntIdentityString 4
+-- Identity ("2",4)
+-- >>> runStateT stateIntIdentityInt'' 4
+-- Identity (2,4)
+-- >>> runStateT stateStringMaybeInt "four"
+-- Just (2,"....")
+-- >>> runStateT stateStringIdentityString "four"
+-- Identity ("2","....")
+-- >>> runStateT stateStringIdentityInt "four"
+-- Identity (2,"....")
+-- >>> runStateT stateIntMaybeString 4
+-- Just ("2",4)
+-- >>> runStateT stateIntMaybeInt' 4
+-- Just (2,4)
+-- >>> runStateT stateIntIdentityString' 4
+-- Identity ("2",4)
+-- >>> runStateT stateIntIdentityInt''' 4
+-- Identity (2,4)
+instance NFunctor StateT where
+  type VarianceStack StateT = InvariantT (Covariant1T (CovariantT (->)))
+  nmap = InvariantT $ \(f1, f1')
+      -> Covariant1T $ \f2
+      -> CovariantT $ \f3
+      -> \body
+      -> StateT $ \s'
+      -> fmap (f3 *** f1) $ unwrapNT f2 $ runStateT body $ f1' s'
+
+-- $
+-- >>> let writerIntIdentityInt    = do {tell [4]; lift $ Identity 2}
+-- >>> let writerIntIdentityString = nmap                                       <#> show $ writerIntIdentityInt
+-- >>> let writerIntMaybeString    = nmap          <##> NT (Just . runIdentity) <#> show $ writerIntIdentityInt
+-- >>> let writerStringMaybeString = nmap <#> show <##> NT (Just . runIdentity) <#> show $ writerIntIdentityInt
+-- >>> runWriterT writerIntIdentityInt
+-- Identity (2,[4])
+-- >>> runWriterT writerIntIdentityString
+-- Identity ("2",[4])
+-- >>> runWriterT writerIntMaybeString
+-- Just ("2",[4])
+-- >>> runWriterT writerStringMaybeString
+-- Just ("2","[4]")
+--
+-- >>> let writerIntIdentityInt'      = nmap                                                                    -#- ()   $ writerIntIdentityInt
+-- >>> let writerIntMaybeInt          = nmap                                       <##> NT (Just . runIdentity) -#- ()   $ writerIntIdentityInt
+-- >>> let writerIntIdentityString    = nmap                                       -#-  ()                      <#> show $ writerIntIdentityInt
+-- >>> let writerIntIdentityInt''     = nmap                                       -#-  ()                      -#- ()   $ writerIntIdentityInt
+-- >>> let writerStringMaybeInt       = nmap <#> show <##> NT (Just . runIdentity) -#- ()   $ writerIntIdentityInt
+-- >>> let writerStringIdentityString = nmap <#> show -#-  ()                      <#> show $ writerIntIdentityInt
+-- >>> let writerStringIdentityInt    = nmap <#> show -#-  ()                      -#- ()   $ writerIntIdentityInt
+-- >>> let writerIntMaybeString       = nmap -#- ()   <##> NT (Just . runIdentity) <#> show $ writerIntIdentityInt
+-- >>> let writerIntMaybeInt'         = nmap -#- ()   <##> NT (Just . runIdentity) -#- ()   $ writerIntIdentityInt
+-- >>> let writerIntIdentityString'   = nmap -#- ()   -#-  ()                      <#> show $ writerIntIdentityInt
+-- >>> let writerIntIdentityInt'''    = nmap -#- ()   -#-  ()                      -#- ()   $ writerIntIdentityInt
+-- >>> runWriterT writerIntIdentityInt'
+-- Identity (2,[4])
+-- >>> runWriterT writerIntMaybeInt
+-- Just (2,[4])
+-- >>> runWriterT writerIntIdentityString
+-- Identity ("2",[4])
+-- >>> runWriterT writerIntIdentityInt''
+-- Identity (2,[4])
+-- >>> runWriterT writerStringMaybeInt
+-- Just (2,"[4]")
+-- >>> runWriterT writerStringIdentityString
+-- Identity ("2","[4]")
+-- >>> runWriterT writerStringIdentityInt
+-- Identity (2,"[4]")
+-- >>> runWriterT writerIntMaybeString
+-- Just ("2",[4])
+-- >>> runWriterT writerIntMaybeInt'
+-- Just (2,[4])
+-- >>> runWriterT writerIntIdentityString'
+-- Identity ("2",[4])
+-- >>> runWriterT writerIntIdentityInt'''
+-- Identity (2,[4])
+instance NFunctor WriterT where
+  type VarianceStack WriterT = CovariantT (Covariant1T (CovariantT (->)))
+  nmap = CovariantT $ \f1
+      -> Covariant1T $ \f2
+      -> CovariantT $ \f3
+      -> \body
+      -> WriterT
+       $ fmap (f3 *** f1) $ unwrapNT f2 $ runWriterT body
+
+-- $
+-- >>> let myConst = Const "foo" :: Const String Double
+-- >>> (nmap            👻#👻 () $ myConst) <&> length
+-- Const "foo"
+-- >>> (nmap <#> length 👻#👻 () $ myConst) <&> length
+-- Const 3
+--
+-- >>> (nmap            -#-   () $ myConst)
+-- Const "foo"
+-- >>> (nmap <#> length -#-   () $ myConst)
+-- Const 3
+-- >>> (nmap -#- ()     👻#👻 () $ myConst) <&> length
+-- Const "foo"
+-- >>> (nmap -#- ()     -#-   () $ myConst)
+-- Const "foo"
+instance NFunctor Const where
+  type VarianceStack Const = CovariantT (PhantomvariantT (->))
+  nmap = CovariantT $ \f1
+      -> PhantomvariantT $ \()
+      -> \(Const a1)
+      -> Const (f1 a1)
+
+
 -- |
 -- For kind @*@, 'nmap' must be the identity function. If 'Bifunctor' and
 -- 'Functor' correspond to binary and unary functors, this corresponds to a
@@ -93,185 +472,201 @@
 -- >>> nmap ()
 -- ()
 instance NFunctor () where
+  type VarianceStack () = (->)
   nmap = id
 
 instance NFunctor Identity where
-  nmap = NMap1 $ \f1
+  type VarianceStack Identity = CovariantT (->)
+  nmap = CovariantT $ \f1
       -> \(Identity x1)
       -> Identity (f1 x1)
 
 instance NFunctor (,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
+  type VarianceStack (,) = CovariantT (CovariantT (->))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
       -> \(x1,x2)
       -> (f1 x1, f2 x2)
 
 instance NFunctor (,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
+  type VarianceStack (,,) = CovariantT (CovariantT (CovariantT (->)))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
       -> \(x1,x2,x3)
       -> (f1 x1, f2 x2, f3 x3)
 
 instance NFunctor (,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
+  type VarianceStack (,,,) = CovariantT (CovariantT (CovariantT (CovariantT (->))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
       -> \(x1,x2,x3,x4)
       -> (f1 x1, f2 x2, f3 x3, f4 x4)
 
 instance NFunctor (,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
+  type VarianceStack (,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
       -> \(x1,x2,x3,x4,x5)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5)
 
 instance NFunctor (,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
+  type VarianceStack (,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
       -> \(x1,x2,x3,x4,x5,x6)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6)
 
 instance NFunctor (,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
+  type VarianceStack (,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
       -> \(x1,x2,x3,x4,x5,x6,x7)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7)
 
 instance NFunctor (,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
+  type VarianceStack (,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
       -> \(x1,x2,x3,x4,x5,x6,x7,x8)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8)
 
 instance NFunctor (,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
+  type VarianceStack (,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9)
 
 instance NFunctor (,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
+  type VarianceStack (,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10)
 
 instance NFunctor (,,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
-      -> NMap1 $ \f11
+  type VarianceStack (,,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
+      -> CovariantT $ \f11
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10, f11 x11)
 
 instance NFunctor (,,,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
-      -> NMap1 $ \f11
-      -> NMap1 $ \f12
+  type VarianceStack (,,,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->))))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
+      -> CovariantT $ \f11
+      -> CovariantT $ \f12
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10, f11 x11, f12 x12)
 
 instance NFunctor (,,,,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
-      -> NMap1 $ \f11
-      -> NMap1 $ \f12
-      -> NMap1 $ \f13
+  type VarianceStack (,,,,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
+      -> CovariantT $ \f11
+      -> CovariantT $ \f12
+      -> CovariantT $ \f13
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10, f11 x11, f12 x12, f13 x13)
 
 instance NFunctor (,,,,,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
-      -> NMap1 $ \f11
-      -> NMap1 $ \f12
-      -> NMap1 $ \f13
-      -> NMap1 $ \f14
+  type VarianceStack (,,,,,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->))))))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
+      -> CovariantT $ \f11
+      -> CovariantT $ \f12
+      -> CovariantT $ \f13
+      -> CovariantT $ \f14
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10, f11 x11, f12 x12, f13 x13, f14 x14)
 
 instance NFunctor (,,,,,,,,,,,,,,) where
-  nmap = NMap1 $ \f1
-      -> NMap1 $ \f2
-      -> NMap1 $ \f3
-      -> NMap1 $ \f4
-      -> NMap1 $ \f5
-      -> NMap1 $ \f6
-      -> NMap1 $ \f7
-      -> NMap1 $ \f8
-      -> NMap1 $ \f9
-      -> NMap1 $ \f10
-      -> NMap1 $ \f11
-      -> NMap1 $ \f12
-      -> NMap1 $ \f13
-      -> NMap1 $ \f14
-      -> NMap1 $ \f15
+  type VarianceStack (,,,,,,,,,,,,,,) = CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (CovariantT (->)))))))))))))))
+  nmap = CovariantT $ \f1
+      -> CovariantT $ \f2
+      -> CovariantT $ \f3
+      -> CovariantT $ \f4
+      -> CovariantT $ \f5
+      -> CovariantT $ \f6
+      -> CovariantT $ \f7
+      -> CovariantT $ \f8
+      -> CovariantT $ \f9
+      -> CovariantT $ \f10
+      -> CovariantT $ \f11
+      -> CovariantT $ \f12
+      -> CovariantT $ \f13
+      -> CovariantT $ \f14
+      -> CovariantT $ \f15
       -> \(x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15)
       -> (f1 x1, f2 x2, f3 x3, f4 x4, f5 x5, f6 x6, f7 x7, f8 x8, f9 x9, f10 x10, f11 x11, f12 x12, f13 x13, f14 x14, f15 x15)
 
diff --git a/test/doctests.hs b/test/doctests.hs
--- a/test/doctests.hs
+++ b/test/doctests.hs
@@ -1,1 +1,10 @@
-{-# OPTIONS_GHC -F -pgmF doctest-discover #-}
+module Main where
+
+import Build_doctests (flags, pkgs, module_sources)
+import Test.DocTest (doctest)
+
+main :: IO ()
+main = do
+    doctest args
+  where
+    args = flags ++ pkgs ++ module_sources
