-- Copyright 2018-2021 Google LLC
--
-- Licensed under the Apache License, Version 2.0 (the "License");
-- you may not use this file except in compliance with the License.
-- You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
-- Unless required by applicable law or agreed to in writing, software
-- distributed under the License is distributed on an "AS IS" BASIS,
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-- See the License for the specific language governing permissions and
-- limitations under the License.

-- | Typeclass hierarchy of functors from @k -> Type@ to @Type@.
--
-- The naming convention @Functor10@ comes from the fact that it's a functor
-- from the category of objects with one type parameter to the category of
-- objects with zero type parameters.  See
-- <http://hackage.haskell.org/package/hakaru-0.4.0/docs/src/Language.Hakaru.Syntax.IClasses.html>
-- for precedent for this naming convention.
--
-- In this, the argument morphisms are of the form @forall a. m a -> n a@, and
-- the result morphisms are of the form @f m -> f n@.
--
-- The main parts of this are:
--
-- * 'Functor10' and the other similarly-named typeclasses, which are
-- essentially just translations of 'Functor' et al. to kind
-- @(k -> Type) -> Type@.
-- These are essentially 'Functor's with additional \"tag\" types
-- available at each occurrence of the argument.  Applying them to
-- @Identity@, you get essentially normal records, but other type parameters
-- give other interesting objects.
--
-- * (':**') and 'Exists' (two stock 'Functor10' types) plus appropriate
-- instances for products, sums, and compositions of functors as provided by
-- "GHC.Generics": (':*:'), (':+:'), and (':.:').
--
-- * 'Entails', which uses a GADT-like value to retrieve instances for its type
-- parameter.  This adds a lot of power to the otherwise-pretty-weak
-- 'Functor10' class hierarchy, since without access to corresponding
-- instances, all the input morphisms are unable to do anything whatsoever with
-- the \"tag\" types.  With 'Entails', though, one can use the fact that every
-- occurrence of @m a@ in @f m@ satisfies @c a@ to make instances of @c@
-- available while mapping/folding/traversing/etc. an @f m@.
--
-- The provided GHC.Generics-based deriving functionality is meant to be used
-- with the DerivingVia extension.  To get the full suite of classes on a
-- generic-record type, make sure every field is either an 'Ap10', another
-- nested generic-record, or an instance of 'Data.Functor.Update' applied to
-- one of the above.  Then, just add the deriving clauses:
--
-- @
--     data MyType f = MyType { _mrInt :: Ap10 Int f, _mrBool :: Ap10 Bool f }
--       deriving Generic1
--       deriving
--         ( Functor10, Foldable10, Traversable10
--         , Applicative10, Representable10, Update10, Constrained10 c
--         ) via Wrapped1 Generic1 MyType
--       deriving
--         ( Functor10WithIndex, Foldable10WithIndex, Traversable10WithIndex
--         ) via Wrapped1 Representable10 MyType
--
--     type instance Index10 MyType = Rep10 MyType
-- @

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE EmptyCase #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}

module Data.Ten
  ( -- * Typeclasses
    -- ** Functor10
    module Data.Ten.Functor
  , module Data.Ten.Functor.WithIndex
    -- ** Foldable10
  , module Data.Ten.Foldable
  , module Data.Ten.Foldable.WithIndex
    -- ** Traversable10
  , module Data.Ten.Traversable
  , module Data.Ten.Traversable.WithIndex
    -- ** Applicative10
  , module Data.Ten.Applicative
    -- ** Representable10
  , module Data.Ten.Representable
    -- ** Update10
  , module Data.Ten.Update
    -- ** Entails
  , module Data.Ten.Entails

    -- * Standard 'Functor10's
  , module Data.Ten.Ap
  , module Data.Ten.Exists
  , module Data.Ten.Field
  , module Data.Ten.Sigma
  , (:.:)(..), (:*:)(..), (:+:)(..)
  ) where

import GHC.Generics ((:.:)(..), (:*:)(..), (:+:)(..))

import Data.Ten.Ap
import Data.Ten.Applicative
import Data.Ten.Entails
import Data.Ten.Exists
import Data.Ten.Field
import Data.Ten.Foldable
import Data.Ten.Foldable.WithIndex
import Data.Ten.Sigma
import Data.Ten.Functor
import Data.Ten.Functor.WithIndex
import Data.Ten.Representable
import Data.Ten.Traversable
import Data.Ten.Traversable.WithIndex
import Data.Ten.Update

-- TODO(awpr):
--
-- class Antimonoidal10 f where -- (Alternative10)
--   nah10 :: f (Const Void)
--   alt10 :: f m -> f m -> f (Sum m n)
--
-- class Contravariant10 f where
--   contramap10 :: (forall a. n a -> m a) -> f m -> f n