n-ary-functor 0.1.0.0 → 1.0
raw patch · 6 files changed
+793/−190 lines, 6 filesdep +n-ary-functordep +natural-transformationdep +transformersdep −doctest-discoverdep ~basebuild-type:Customsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: n-ary-functor, natural-transformation, transformers
Dependencies removed: doctest-discover
Dependency ranges changed: base
API changes (from Hackage documentation)
- NAryFunctor: NMap1 :: (forall a b. (a -> b) -> NMap k (f a) (f' b)) -> NMap1 k
- NAryFunctor: instance NAryFunctor.NFunctor (Data.Either.Either a)
- NAryFunctor: newtype NMap1 k (f :: Type -> k) (f' :: Type -> k)
+ NAryFunctor: (-#-) :: VarianceTransformer t a => t inner f g -> () -> inner (f a) (g a)
+ NAryFunctor: Contravariant1T :: (forall m m'. (Functor m, Functor m') => m' :~> m -> f m `to` f' m') -> Contravariant1T to f f'
+ NAryFunctor: ContravariantT :: (forall a a'. (a' -> a) -> f a `to` f' a') -> ContravariantT to f f'
+ NAryFunctor: Covariant1T :: (forall m m'. (Functor m, Functor m') => m :~> m' -> f m `to` f' m') -> Covariant1T to f f'
+ NAryFunctor: CovariantT :: (forall a a'. (a -> a') -> f a `to` f' a') -> CovariantT to f f'
+ NAryFunctor: Invariant1T :: (forall m m'. (Functor m, Functor m') => (m :~> m', m' :~> m) -> f m `to` f' m') -> Invariant1T to f f'
+ NAryFunctor: InvariantT :: (forall a a'. (a -> a', a' -> a) -> f a `to` f' a') -> InvariantT to f f'
+ NAryFunctor: NonvariantT :: (forall a a'. (a ~ a') => f a `to` f' a') -> NonvariantT to f f'
+ NAryFunctor: PhantomvariantT :: (forall a a'. () -> f a `to` f' a') -> PhantomvariantT to f f'
+ NAryFunctor: [<##>/>##<] :: Invariant1T to f f' -> forall m m'. (Functor m, Functor m') => (m :~> m', m' :~> m) -> f m `to` f' m'
+ NAryFunctor: [<##>] :: Covariant1T to f f' -> forall m m'. (Functor m, Functor m') => m :~> m' -> f m `to` f' m'
+ NAryFunctor: [<#>/>#<] :: InvariantT to f f' -> forall a a'. (a -> a', a' -> a) -> f a `to` f' a'
+ NAryFunctor: [>##<] :: Contravariant1T to f f' -> forall m m'. (Functor m, Functor m') => m' :~> m -> f m `to` f' m'
+ NAryFunctor: [>#<] :: ContravariantT to f f' -> forall a a'. (a' -> a) -> f a `to` f' a'
+ NAryFunctor: [unNonvariant] :: NonvariantT to f f' -> forall a a'. (a ~ a') => f a `to` f' a'
+ NAryFunctor: [👻#👻] :: PhantomvariantT to f f' -> forall a a'. () -> f a `to` f' a'
+ NAryFunctor: class VarianceTransformer (t :: (k -> k -> *) -> (k1 -> k) -> (k1 -> k) -> *) (a :: k1)
+ NAryFunctor: instance GHC.Base.Functor m => NAryFunctor.VarianceTransformer NAryFunctor.Contravariant1T m
+ NAryFunctor: instance GHC.Base.Functor m => NAryFunctor.VarianceTransformer NAryFunctor.Covariant1T m
+ NAryFunctor: instance GHC.Base.Functor m => NAryFunctor.VarianceTransformer NAryFunctor.Invariant1T m
+ NAryFunctor: instance NAryFunctor.NFunctor (->)
+ NAryFunctor: instance NAryFunctor.NFunctor Control.Monad.Trans.Reader.ReaderT
+ NAryFunctor: instance NAryFunctor.NFunctor Control.Monad.Trans.State.Lazy.StateT
+ NAryFunctor: instance NAryFunctor.NFunctor Control.Monad.Trans.Writer.Lazy.WriterT
+ NAryFunctor: instance NAryFunctor.NFunctor Data.Functor.Const.Const
+ NAryFunctor: instance NAryFunctor.VarianceTransformer NAryFunctor.ContravariantT a
+ NAryFunctor: instance NAryFunctor.VarianceTransformer NAryFunctor.CovariantT a
+ NAryFunctor: instance NAryFunctor.VarianceTransformer NAryFunctor.InvariantT a
+ NAryFunctor: instance forall k k1 (a :: k1). NAryFunctor.VarianceTransformer NAryFunctor.NonvariantT a
+ NAryFunctor: instance forall k k1 (a :: k1). NAryFunctor.VarianceTransformer NAryFunctor.PhantomvariantT a
+ NAryFunctor: instance forall k k1 (f :: k1 -> k) (t :: (k -> k -> GHC.Types.*) -> (k1 -> k) -> (k1 -> k) -> GHC.Types.*) (inner :: k -> k -> GHC.Types.*) (a :: k1). (NAryFunctor.NFunctor f, NAryFunctor.VarianceStack f ~ t inner, NAryFunctor.VarianceTransformer t a) => NAryFunctor.NFunctor (f a)
+ NAryFunctor: newtype Contravariant1T to f f'
+ NAryFunctor: newtype ContravariantT to f f'
+ NAryFunctor: newtype Covariant1T to f f'
+ NAryFunctor: newtype CovariantT to f f'
+ NAryFunctor: newtype Invariant1T to f f'
+ NAryFunctor: newtype InvariantT to f f'
+ NAryFunctor: newtype NonvariantT to f f'
+ NAryFunctor: newtype PhantomvariantT to f f'
+ NAryFunctor: type family VarianceStack f :: k -> k -> *;
+ NAryFunctor: }
- NAryFunctor: [<#>] :: NMap1 k -> forall a b. (a -> b) -> NMap k (f a) (f' b)
+ NAryFunctor: [<#>] :: CovariantT to f f' -> forall a a'. (a -> a') -> f a `to` f' a'
- NAryFunctor: class NFunctor (f :: k)
+ NAryFunctor: class NFunctor (f :: k) where type VarianceStack f :: k -> k -> * where {
- NAryFunctor: nmap :: NFunctor f => NMap k f f
+ NAryFunctor: nmap :: NFunctor f => VarianceStack f f f
Files
- CHANGELOG.md +29/−0
- README.md +154/−8
- Setup.hs +6/−2
- n-ary-functor.cabal +27/−7
- src/NAryFunctor.hs +567/−172
- test/doctests.hs +10/−1
CHANGELOG.md view
@@ -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
README.md view
@@ -1,14 +1,160 @@-# N-ary Functors+# N-ary Functors [](https://hackage.haskell.org/package/n-ary-functor) [](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)+```
Setup.hs view
@@ -1,2 +1,6 @@-import Distribution.Simple-main = defaultMain+module Main where++import Distribution.Extra.Doctest (defaultMainWithDoctests)++main :: IO ()+main = defaultMainWithDoctests "doctests"
n-ary-functor.cabal view
@@ -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
src/NAryFunctor.hs view
@@ -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)
test/doctests.hs view
@@ -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