    -----------------------------------------------------------------------------
    -- |
    -- Module:  Barbies
    --
    -- A common Haskell idiom is to parameterise a datatype by a functor or GADT
    -- (or any "indexed type" @k -> 'Data.Kind.Type'@), a pattern
    -- sometimes called <https://reasonablypolymorphic.com/blog/higher-kinded-data/ HKD>).
    -- This parameter acts like the outfit of a Barbie, turning it into a different
    -- doll. The canonical example would be:
    --
    -- @
    -- data Person f
    --   = Person
    --       { name :: f 'String'
    --       , age  :: f 'Int'
    --       }
    -- @
    --
    -- Let's say that we are writing an application where @Person@ data
    -- will be read from a web form, validated, and stored in a database. Some
    -- possibles outfits that we could use along the way are:
    --
    -- @
    -- Person ('Data.Functor.Const.Const' 'String')  -- for the raw input from the web-form,
    -- Person ('Either' 'String') -- for the result of parsing and validating,
    -- Person 'Data.Functor.Identity.Identity'        -- for the actual data,
    -- Person DbColumn        -- To describe how to read / write a @Person@ to the db
    --
    -- data DbColumn a
    --   = DbColumn
    --       { colName :: 'String'
    --       , fromDb  :: DbDataParser a
    --       , toDb    :: a -> DbData
    --       }
    -- @
    --
    -- In such application it is likely that one will have lots of types like
    -- @Person@ so we will like to handle these transformations uniformly,
    -- without boilerplate or repetitions.  This package provides classes to
    -- manipulate these types, using notions that are familiar to haskellers like
    -- 'Functor', 'Applicative' or 'Traversable'. For example, instead of writing
    -- an ad-hoc function that checks that all fields have a correct value, like
    --
    -- @
    -- checkPerson :: Person ('Either' 'String') -> 'Either' ['String'] (Person 'Data.Functor.Identity.Identity')
    -- @
    --
    -- we can write only one such function:
    --
    -- @
    -- check :: 'TraversableB' b => b ('Either' 'String') -> 'Either' ['String'] (b 'Data.Functor.Identity.Identity')
    -- check be
    --   = case 'btraverse' ('either' ('const' 'Nothing') ('Just' . 'Daa.Functor.Identity.Identity')) be of
    --       'Just' bi -> 'Right' bi
    --       'Nothing' -> 'Left' ('bfoldMap' ('either' (:[]) ('const' [])) be)
    -- @
    --
    --  Moreover, these classes come with default instances based on
    -- `GHC.Generics.Generic`, so using them is as easy as:
    --
    -- @
    -- data Person f
    --   = Person
    --       { name :: f 'String'
    --       , age  :: f 'Int'
    --       }
    --   deriving
    --     ( 'GHC.Generics.Generic'
    --     , 'FunctorB', 'TraversableB', 'ApplicativeB', 'ConstraintsB'
    --     )
    --
    -- deriving instance 'AllBF' 'Show' f Person => 'Show' (Person f)
    -- deriving instance 'AllBF' 'Eq'   f Person => 'Eq'   (Person f)
    -- @
    --

    -----------------------------------------------------------------------------
    module Barbies
      (  -- * Barbies are functors

         -- | Barbie-types are functors. That means that if one is familiar
         --   with standard classes like 'Functor', 'Applicative' or 'Traversable',
         --   one already knows how to work with barbie-types too. For instance, just
         --   like one would use:
         --
         -- @
         -- 'fmap' f (as :: [a])
         -- @
         --
         --   to apply @f@ uniformly on every @a@ occurring
         --   in @as@, one could use the following to turn a 'Either'-outfit
         --   into 'Maybe'-outfit:
         --
         -- @
         -- 'bmap' ('either' ('const' 'Nothing') 'Just') (p :: Person ('Either' e))
         -- @
         --
         --   In this case, the argument of 'bmap' will have to be applied on all
         --   fields of @p@:
         --
         -- @
         -- name p :: 'Either' e 'String'
         -- age  p :: 'Either' e 'Int'
         -- @
         --
         --   So 'bmap' here demands a polymorphic function of type:
         --
         -- @
         -- forall a . 'Either' e a -> 'Maybe' a
         -- @
         --
         --   That is why `bmap` has a rank-2 type:
         --
         -- @
         -- 'bmap' :: 'FunctorB' b => (forall a. f a -> g a) -> b f -> b g
         -- @
         --
         --   Polymorphic functions with 'Applicative' effects can be applied
         --   using 'btraverse' and the effects will be accumulated:
         --
         -- @
         -- 'btraverse' :: ('TraversableB' b, 'Applicative' t) => (forall a. f a -> t (g a)) -> b f -> t (b g)
         -- @
         --
         --   Finally, some barbie-types (typically records like @Person@) have an
         --   'Applicative' structure, and allow us to lift pure n-ary functions
         --   to functions on barbie-types. For example, 'bzipWith' gives us an analogous
         --   of 'Control.Applicative.liftA2':
         --
         -- @
         -- 'bzipWith' :: 'ApplicativeB' b => (forall a. f a -> g a -> h a) -> b f -> b g -> b h
         -- @
         --
         -- We can use this to combine barbies:
         --
         -- @
         -- addDefaults :: Person 'Maybe' -> Person 'Data.Functor.Identity' -> Person 'Data.Functor.Identity'
         -- addDefaults = 'bzipWith' (\\m d -> 'maybe' d 'pure' m)
         -- @
         --
         --   Why is there not a @MonadB@ class as well? As everyone knows,
         --   <https://james-iry.blogspot.com/2009/05/brief-incomplete-and-mostly-wrong.html a monad is just a monoid in the category of endofunctors>,
         --   which in this case is a problem, since barbie-types are not endofunctors:
         --   they map indexed-types to types, unlike the 'Functor' class, that
         --   captures endo-functors on 'Data.Kind.Type'.
         --
         --  All these classes, and other convenient functions are found in:
         module Data.Functor.Barbie

         -- * Transformers are functors

         -- | Haskellers may be more used to playing with another family of dolls:
         --   <https://hackage.haskell.org/package/transformers transformers>.
         --   Consider for example the following functor-transformers:
         --
         -- @
         -- 'Data.Functor.Compose.Compose' g f a
         -- 'Control.Monad.Trans.Reader.ReaderT' r f a
         -- 'Control.Monad.Maybe.MaybeT' f a
         -- @
         --
         --  Like with barbies, we can think that different choices of @f@ will
         --  give us a different doll. And if we start thinking about how
         --  to change the outfit of a transformer, we notice that, just like
         --  barbie-types, transformer-types are functors too.
         --
         -- @
         -- 'tmap' :: 'FunctorT' t => (forall a. f a -> g a) -> t f x -> b g x
         -- @
         --
         --  Where 'FunctorB' captures functors from indexed-types to types,
         --  'FunctorT' captures those between indexed-types. And again, we can
         --  identitfy familiar classes of functors: 'ApplicativeT' and 'TraversableT'.
         --
         -- Now, transformers like the ones above, are actually endofunctors, e.g.
         -- they map @'Data.Kind.Type' -> 'Data.Kind.Type'@ to itself. So it makes
         -- sense to classify those that are actually monads: the 'MonadT' class
         -- gives us a notion similar to that of `Control.Monad.Trans.Class.MonadTrans',
         -- in that it lets us lift a value to its transformed version:
         --
         -- @
         -- 'tlift' :: 'MonadT' t => f a -> t f a
         --
         --  -- E.g., using the instance for Compose:
         -- 'tlift' [1, 2, 3] = 'Data.Functor.Compose.Compose' ('Just' [1, 2, 3]) :: 'Data.Functor.Compose' 'Maybe' [] 'Int'
         -- @
         --
         -- Unlike all other classes in this package, 'MonadT' instances need to be written
         -- by hand.
         --
         -- For further details, see:

       , module Data.Functor.Transformer

         -- * Bi-functors and nesting
         --
         -- | A barbie-type that is parametric on an additional functor can be made an
         -- instance of both 'FunctorB' and 'FunctorT'. For example:
         --
         -- @
         -- data B f g = B (f Int) (g Bool)
         --   deriving (Generic)
         --
         -- instance FunctorB (B f)
         -- instance FunctorT B
         -- @
         --
         -- This gives us a a bifunctor on indexed-types, as we can map
         -- simultaneously over both arguments using 'btmap':
         --
         -- @
         -- 'btmap' :: ('FunctorB' (b f), 'FunctorT' b) => (forall a . f a -> f' a) -> (forall a . g a -> g' a) -> b f g -> b f' g'
         -- @
         --
         -- When @f ~ g@, we can use a specialized version of 'btmap':
         --
         -- @
         -- 'btmap1' :: ('FunctorB' (b f), 'FunctorT' b) => (forall a . f a -> f' a) -> b f f -> b f' f'
         -- @
         --
         -- Functions like 'btmap1' can be useful to handle cases where we would like
         -- a barbie-type to occur under the functor-argument. Let's consider an example
         -- of this. Continuing the web form example above, one may want to find out
         -- about a person's dependants and model it as follows:
         --
         -- @
         -- newtype Dependants f
         --   = Dependants { getDependants :: f [Person f] }
         -- @
         --
         -- This has the appeal of letting us distinguish two states:
         --
         -- @
         -- Dependants { getDependants = Just [] }  -- the user declared 0 dependants
         -- Dependants { getDependants = Nothing }  -- the user didn't specify dependants yet
         -- @
         --
         -- Unfortunately, it is not possible to write a 'FunctorB' instance for such
         -- a type (before going on, try to write one yourself!). Intuitively, we would
         -- need to have @'Functor' f@, which we can't assume. However, such a type
         -- can be rewritten as follows:
         --
         -- @
         -- newtype Dependants f' f
         --   = Dependants { getDependants :: f' [Person f] }
         --   deriving (Generic)
         --
         -- instance Functor f' => FunctorB (Dependants f')
         -- instance FunctorT Dependants
         --
         -- type Dependants f = Dependants f f
         -- @
         --
         -- We can thus use 'btmap1' as a poor man's version of 'bmap' for 'Dependants'.
         --
         -- For more details, see:
       , module Barbies.Bi

         -- * Container-barbies

         -- | Some clothes make barbies look like containers, and we can make those
         --   types behave like normal 'Functor's.

       , Containers.Container(..)
       , Containers.ErrorContainer(..)

        -- * Wrappers

        -- | This can be use with deriving via to automate derivation of instances
        --   for Barbie-types.
       , Wrappers.Barbie(..)

        -- * Trivial Barbies
      , Trivial.Void
      , Trivial.Unit (..)
      ) where

    import Barbies.Internal.Containers as Containers

    import Data.Functor.Barbie
    import Data.Functor.Transformer
    import Barbies.Bi
    import qualified Barbies.Internal.Trivial as Trivial
    import qualified Barbies.Internal.Wrappers as Wrappers