n-ary-functor-1.0: An n-ary version of Functor

Safe HaskellSafe
LanguageHaskell2010

NAryFunctor

Synopsis

Documentation

class NFunctor f where Source #

A generalization of Functor, Bifunctor, Contravariant, Profunctor, etc.

  • (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.

The associated type VarianceStack specifies the variance of all the type parameters using a stack of VarianceTransformers ending with (->).

Example instance:

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       = nmap -#- () = id
nmap     >#< id       = nmap -#- () = id
nmap <#>/>#< (id, id) = nmap -#- () = id
...
nmap -#- () -#- () <#> f =
nmap        -#- () <#> f =
nmap               <#> f
(nmap <#> f1 <#> f2) . (nmap <#> g1 <#> g2) = nmap <#> (f1 . g1) <#> (f2 . g2)
(nmap >#< f1 >#< f2) . (nmap >#< g1 >#< g2) = nmap >#< (g1 . f1) >#< (g2 . f2)
...

Minimal complete definition

nmap

Associated Types

type VarianceStack f :: k -> k -> * Source #

Methods

nmap :: VarianceStack f f f Source #

Instances

(NFunctor (k1 -> k) f, (~) ((k1 -> k) -> (k1 -> k) -> *) (VarianceStack (k1 -> k) f) (t inner), VarianceTransformer k1 k t a) => NFunctor k (f a) Source #

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.

Associated Types

type VarianceStack (f a) (f :: f a) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (f a) f f f Source #

NFunctor * () Source #

For kind *, nmap must be the identity function. If Bifunctor and Functor correspond to binary and unary functors, this corresponds to a "nullary" functor.

>>> nmap ()
()

Associated Types

type VarianceStack () (f :: ()) :: k -> k -> * Source #

Methods

nmap :: VarianceStack () f f f Source #

NFunctor (* -> (* -> *) -> * -> *) WriterT Source # 

Associated Types

type VarianceStack WriterT (f :: WriterT) :: k -> k -> * Source #

NFunctor (* -> (* -> *) -> * -> *) StateT Source # 

Associated Types

type VarianceStack StateT (f :: StateT) :: k -> k -> * Source #

Methods

nmap :: VarianceStack StateT f f f Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,,,,,,) (f :: (,,,,,,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,,,,,) (f :: (,,,,,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,,,,) (f :: (,,,,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,,,) (f :: (,,,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,,) (f :: (,,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,,) (f :: (,,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,,) (f :: (,,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> * -> *) (,,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,,) (f :: (,,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> * -> *) (,,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,,) (f :: (,,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> * -> *) (,,,,,) Source # 

Associated Types

type VarianceStack (,,,,,) (f :: (,,,,,)) :: k -> k -> * Source #

NFunctor (* -> * -> * -> * -> * -> *) (,,,,) Source # 

Associated Types

type VarianceStack (,,,,) (f :: (,,,,)) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (,,,,) f f f Source #

NFunctor (* -> * -> * -> * -> *) (,,,) Source # 

Associated Types

type VarianceStack (,,,) (f :: (,,,)) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (,,,) f f f Source #

NFunctor (* -> * -> * -> *) (,,) Source # 

Associated Types

type VarianceStack (,,) (f :: (,,)) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (,,) f f f Source #

NFunctor (* -> * -> *) (->) Source # 

Associated Types

type VarianceStack (->) (f :: (->)) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (->) f f f Source #

NFunctor (* -> * -> *) Either Source # 

Associated Types

type VarianceStack Either (f :: Either) :: k -> k -> * Source #

Methods

nmap :: VarianceStack Either f f f Source #

NFunctor (* -> * -> *) (,) Source # 

Associated Types

type VarianceStack (,) (f :: (,)) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (,) f f f Source #

NFunctor (* -> *) Identity Source # 

Associated Types

type VarianceStack Identity (f :: Identity) :: k -> k -> * Source #

NFunctor (* -> k -> *) (Const k) Source # 

Associated Types

type VarianceStack (Const k) (f :: Const k) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (Const k) f f f Source #

NFunctor (* -> (* -> *) -> * -> *) (ReaderT *) Source # 

Associated Types

type VarianceStack (ReaderT *) (f :: ReaderT *) :: k -> k -> * Source #

Methods

nmap :: VarianceStack (ReaderT *) f f f Source #

class VarianceTransformer t a where Source #

This library uses a stack of VarianceTransformers 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.

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.

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 ().

Minimal complete definition

(-#-)

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

Instances

VarianceTransformer k1 k (NonvariantT k1 k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

VarianceTransformer k1 k (PhantomvariantT k1 k1 k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

VarianceTransformer * k (InvariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

VarianceTransformer * k (ContravariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

VarianceTransformer * k (CovariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

Functor m => VarianceTransformer (* -> *) k (Invariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

Functor m => VarianceTransformer (* -> *) k (Contravariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

Functor m => VarianceTransformer (* -> *) k (Covariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype CovariantT to f f' Source #

Constructors

CovariantT 

Fields

  • (<#>) :: forall a a'. (a -> a') -> f a `to` f' a'
     

Instances

VarianceTransformer * k (CovariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype Covariant1T to f f' Source #

Constructors

Covariant1T 

Fields

Instances

Functor m => VarianceTransformer (* -> *) k (Covariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype ContravariantT to f f' Source #

Constructors

ContravariantT 

Fields

  • (>#<) :: forall a a'. (a' -> a) -> f a `to` f' a'
     

Instances

VarianceTransformer * k (ContravariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype Contravariant1T to f f' Source #

Constructors

Contravariant1T 

Fields

Instances

Functor m => VarianceTransformer (* -> *) k (Contravariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype InvariantT to f f' Source #

Constructors

InvariantT 

Fields

  • (<#>/>#<) :: forall a a'. (a -> a', a' -> a) -> f a `to` f' a'
     

Instances

VarianceTransformer * k (InvariantT k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype Invariant1T to f f' Source #

Constructors

Invariant1T 

Fields

Instances

Functor m => VarianceTransformer (* -> *) k (Invariant1T k k) m Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype NonvariantT to f f' Source #

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 (-#-).

Constructors

NonvariantT 

Fields

Instances

VarianceTransformer k1 k (NonvariantT k1 k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #

newtype PhantomvariantT to f f' Source #

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.

Constructors

PhantomvariantT 

Fields

Instances

VarianceTransformer k1 k (PhantomvariantT k1 k1 k k) a Source # 

Methods

(-#-) :: t inner f g -> () -> inner (f a) (g a) Source #