content: {-# LANGUAGE PolyKinds, UndecidableInstances #-}
  {-# OPTIONS_GHC -fno-warn-unused-binds #-}
  -- | Main module of @generics-sop@
  --
  -- In most cases, you will probably want to import just this module,
  -- and possibly "Generics.SOP.TH" if you want to use Template Haskell
  -- to generate 'Generic' instances for you.
  --
  -- = Generic programming with sums of products
  --
  -- You need this library if you want to define your own generic functions
  -- in the sum-of-products SOP style. Generic programming in the SOP style
  -- follows the following idea:
  --
  --   1.  A large class of datatypes can be viewed in a uniform, structured
  --       way: the choice between constructors is represented using an n-ary
  --       sum (called 'NS'), and the arguments of each constructor are
  --       represented using an n-ary product (called 'NP').
  --
  --   2.  The library captures the notion of a datatype being representable
  --       in the following way. There is a class 'Generic', which for a given
  --       datatype @A@, associates the isomorphic SOP representation with
  --       the original type under the name @'Rep' A@. The class also provides
  --       functions 'from' and 'to' that convert between @A@ and @'Rep' A@ and
  --       witness the isomorphism.
  --
  --   3.  Since all 'Rep' types are sums of products, you can define
  --       functions over them by performing induction on the structure, or
  --       by using predefined combinators that the library provides. Such
  --       functions then work for all 'Rep' types.
  --
  --   4.  By combining the conversion functions 'from' and 'to' with the
  --       function that works on 'Rep' types, we obtain a function that works
  --       on all types that are in the 'Generic' class.
  --
  --   5.  Most types can very easily be made an instance of 'Generic'. For
  --       example, if the datatype can be represented using GHC's built-in
  --       approach to generic programming and has an instance for the
  --       'GHC.Generics.Generic' class from module "GHC.Generics", then an
  --       instance of the SOP 'Generic' can automatically be derived. There
  --       is also Template Haskell code in "Generics.SOP.TH" that allows to
  --       auto-generate an instance of 'Generic' for most types.
  --
  -- = Example
  --
  -- == Instantiating a datatype for use with SOP generics
  --
  -- Let's assume we have the datatypes:
  --
  -- > data A   = C Bool | D A Int | E (B ())
  -- > data B a = F | G a Char Bool
  --
  -- To create 'Generic' instances for @A@ and @B@ via "GHC.Generics", we say
  --
  -- > {-# LANGUAGE DeriveGeneric #-}
  -- >
  -- > import qualified GHC.Generics as GHC
  -- > import Generics.SOP
  -- >
  -- > data A   = C Bool | D A Int | E (B ())
  -- >   deriving (Show, GHC.Generic)
  -- > data B a = F | G a Char Bool
  -- >   deriving (Show, GHC.Generic)
  -- >
  -- > instance Generic A     -- empty
  -- > instance Generic (B a) -- empty
  --
  -- Now we can convert between @A@ and @'Rep' A@ (and between @B@ and @'Rep' B@).
  -- For example,
  --
  -- >>> from (D (C True) 3) :: Rep A
  -- SOP (S (Z (I (C True) :* I 3 :* Nil)))
  -- >>> to it :: A
  -- D (C True) 3
  --
  -- Note that the transformation is shallow: In @D (C True) 3@, the
  -- inner value @C True@ of type @A@ is not affected by the
  -- transformation.
  --
  -- For more details about @'Rep' A@, have a look at the
  -- "Generics.SOP.Universe" module.
  --
  -- == Defining a generic function
  --
  -- As an example of a generic function, let us define a generic
  -- version of 'Control.DeepSeq.rnf' from the @deepseq@ package.
  --
  -- The type of 'Control.DeepSeq.rnf' is
  --
  -- @
  -- NFData a => a -> ()
  -- @
  --
  -- and the idea is that for a term @x@ of type @a@ in the
  -- 'Control.DeepSeq.NFData' class, @rnf x@ forces complete evaluation
  -- of @x@ (i.e., evaluation to /normal form/), and returns @()@.
  --
  -- We call the generic version of this function @grnf@. A direct
  -- definition in SOP style, making use of structural recursion on the
  -- sums and products, looks as follows:
  --
  -- @
  -- grnf :: ('Generic' a, 'All2' NFData ('Code' a)) => a -> ()
  -- grnf x = grnfS ('from' x)
  --
  -- grnfS :: ('All2' NFData xss) => 'SOP' 'I' xss -> ()
  -- grnfS ('SOP' ('Z' xs))  = grnfP xs
  -- grnfS ('SOP' ('S' xss)) = grnfS ('SOP' xss)
  --
  -- grnfP :: ('All' NFData xs) => 'NP' 'I' xs -> ()
  -- grnfP 'Nil'         = ()
  -- grnfP ('I' x ':*' xs) = x \`deepseq\` (grnfP xs)
  -- @
  --
  -- The @grnf@ function performs the conversion between @a@ and @'Rep' a@
  -- by applying 'from' and then applies @grnfS@. The type of @grnf@
  -- indicates that @a@ must be in the 'Generic' class so that we can
  -- apply 'from', and that all the components of @a@ (i.e., all the types
  -- that occur as constructor arguments) must be in the 'NFData' class
  -- ('All2').
  --
  -- The function @grnfS@ traverses the outer sum structure of the
  -- sum of products (note that @'Rep' a = 'SOP' 'I' ('Code' a)@). It
  -- encodes which constructor was used to construct the original
  -- argument of type @a@. Once we've found the constructor in question
  -- ('Z'), we traverse the arguments of that constructor using @grnfP@.
  --
  -- The function @grnfP@ traverses the product structure of the
  -- constructor arguments. Each argument is evaluated using the
  -- 'Control.DeepSeq.deepseq' function from the 'Control.DeepSeq.NFData'
  -- class. This requires that all components of the product must be
  -- in the 'NFData' class ('All') and triggers the corresponding
  -- constraints on the other functions. Once the end of the product
  -- is reached ('Nil'), we return @()@.
  --
  -- == Defining a generic function using combinators
  --
  -- In many cases, generic functions can be written in a much more
  -- concise way by avoiding the explicit structural recursion and
  -- resorting to the powerful combinators provided by this library
  -- instead.
  --
  -- For example, the @grnf@ function can also be defined as a one-liner
  -- as follows:
  --
  -- @
  -- grnf :: ('Generic' a, 'All2' NFData ('Code' a)) => a -> ()
  -- grnf = 'rnf' . 'hcollapse' . 'hcmap' ('Proxy' :: 'Proxy' NFData) ('mapIK' rnf) . 'from'
  -- @
  --
  -- 'mapIK' and friends ('mapII', 'mapKI', etc.) are small helpers for working
  -- with 'I' and 'K' functors, for example 'mapIK' is defined as
  -- @'mapIK' f = \\ ('I' x) -> 'K' (f x)@
  --
  -- The following interaction should provide an idea of the individual
  -- transformation steps:
  --
  -- >>> let x = G 2.5 'A' False :: B Double
  -- >>> from x
  -- SOP (S (Z (I 2.5 :* I 'A' :* I False :* Nil)))
  -- >>> hcmap (Proxy :: Proxy NFData) (mapIK rnf) it
  -- SOP (S (Z (K () :* K () :* K () :* Nil)))
  -- >>> hcollapse it
  -- [(),(),()]
  -- >>> rnf it
  -- ()
  --
  -- The 'from' call converts into the structural representation.
  -- Via 'hcmap', we apply 'rnf' to all the components. The result
  -- is a sum of products of the same shape, but the components are
  -- no longer heterogeneous ('I'), but homogeneous (@'K' ()@). A
  -- homogeneous structure can be collapsed ('hcollapse') into a
  -- normal Haskell list. Finally, 'rnf' actually forces evaluation
  -- of this list (and thereby actually drives the evaluation of all
  -- the previous steps) and produces the final result.
  --
  -- == Using a generic function
  --
  -- We can directly invoke 'grnf' on any type that is an instance of
  -- class 'Generic'.
  --
  -- >>> grnf (G 2.5 'A' False)
  -- ()
  -- >>> grnf (G 2.5 undefined False)
  -- *** Exception: Prelude.undefined
  -- ...
  --
  -- Note that the type of 'grnf' requires that all components of the
  -- type are in the 'Control.DeepSeq.NFData' class. For a recursive
  -- datatype such as @B@, this means that we have to make @A@
  -- (and in this case, also @B@) an instance of 'Control.DeepSeq.NFData'
  -- in order to be able to use the 'grnf' function. But we can use 'grnf'
  -- to supply the instance definitions:
  --
  -- > instance NFData A where rnf = grnf
  -- > instance NFData a => NFData (B a) where rnf = grnf
  --
  -- = More examples
  --
  -- The best way to learn about how to define generic functions in the SOP style
  -- is to look at a few simple examples. Examples are provided by the following
  -- packages:
  --
  --   * @<http://hackage.haskell.org/package/basic-sop basic-sop>@ basic examples,
  --   * @<http://hackage.haskell.org/package/pretty-sop pretty-sop>@ generic pretty printing,
  --   * @<http://hackage.haskell.org/package/lens-sop lens-sop>@ generically computed lenses,
  --   * @<http://hackage.haskell.org/package/json-sop json-sop>@ generic JSON conversions.
  --
  -- The generic functions in these packages use a wide variety of the combinators
  -- that are offered by the library.
  --
  -- = Paper
  --
  -- A detailed description of the ideas behind this library is provided by
  -- the paper:
  --
  --   * Edsko de Vries and Andres Löh.
  --     <http://www.andres-loeh.de/TrueSumsOfProducts True Sums of Products>.
  --     Workshop on Generic Programming (WGP) 2014.
  --
  --
  module Generics.SOP (
      -- * Codes and interpretations
      Generic(..)
    , Rep
    , IsProductType
    , ProductCode
    , productTypeFrom
    , productTypeTo
    , IsEnumType
    , enumTypeFrom
    , enumTypeTo
    , IsWrappedType
    , WrappedCode
    , wrappedTypeFrom
    , wrappedTypeTo
    , IsNewtype
    , newtypeFrom
    , newtypeTo
      -- * n-ary datatypes
    , NP(..)
    , NS(..)
    , SOP(..)
    , unSOP
    , POP(..)
    , unPOP
      -- * Metadata
    , DatatypeInfo(..)
    , moduleName
    , datatypeName
    , constructorInfo
    , ConstructorInfo(..)
    , constructorName
    , FieldInfo(..)
    , fieldName
    , HasDatatypeInfo(..)
    , DatatypeName
    , ModuleName
    , ConstructorName
    , FieldName
    , Associativity(..)
    , Fixity
      -- * Combinators
      -- ** Constructing products
    , HPure(..)
      -- ** Destructing products
    , hd
    , tl
    , Projection
    , projections
    , shiftProjection
      -- ** Application
    , type (-.->)(..)
    , fn
    , fn_2
    , fn_3
    , fn_4
    , Prod
    , HAp(..)
      -- ** Lifting / mapping
    , hliftA
    , hliftA2
    , hliftA3
    , hcliftA
    , hcliftA2
    , hcliftA3
    , hmap
    , hzipWith
    , hzipWith3
    , hcmap
    , hczipWith
    , hczipWith3
      -- ** Constructing sums
    , Injection
    , injections
    , shift
    , shiftInjection
    , UnProd
    , HApInjs(..)
    , apInjs_NP  -- deprecated export
    , apInjs_POP -- deprecated export
      -- ** Destructing sums
    , unZ
    , HIndex(..)
    , Ejection
    , ejections
    , shiftEjection
      -- ** Dealing with @'All' c@
    , hcliftA'
    , hcliftA2'
    , hcliftA3'
      -- ** Comparison
    , compare_NS
    , ccompare_NS
    , compare_SOP
    , ccompare_SOP
      -- ** Collapsing
    , CollapseTo
    , HCollapse(..)
      -- ** Folding and sequencing
    , HTraverse_(..)
    , hcfoldMap
    , hcfor_
    , HSequence(..)
    , hsequence
    , hsequenceK
    , hctraverse
    , hcfor
      -- ** Expanding sums to products
    , HExpand(..)
      -- ** Transformation of index lists and coercions
    , HTrans(..)
    , hfromI
    , htoI
      -- ** Partial operations
    , fromList
      -- * Utilities
      -- ** Basic functors
    , K(..)
    , unK
    , I(..)
    , unI
    , (:.:)(..)
    , unComp
      -- *** Mapping functions
    , mapII
    , mapIK
    , mapKI
    , mapKK
    , mapIII
    , mapIIK
    , mapIKI
    , mapIKK
    , mapKII
    , mapKIK
    , mapKKI
    , mapKKK
      -- ** Mapping constraints
    , All
    , All2
    , cpara_SList
    , ccase_SList
    , AllZip
    , AllZip2
    , AllN
    , AllZipN
      -- ** Other constraints
    , Compose
    , And
    , Top
    , LiftedCoercible
    , SameShapeAs
      -- ** Singletons
    , SList(..)
    , SListI
    , SListI2
    , sList
    , para_SList
    , case_SList
      -- *** Shape of type-level lists
    , Shape(..)
    , shape
    , lengthSList
      -- ** Re-exports
  
  -- Workaround for lack of MIN_TOOL_VERSION macro in Cabal 1.18, see:
  -- https://github.com/well-typed/generics-sop/issues/3
  #ifndef MIN_TOOL_VERSION_haddock
  #define MIN_TOOL_VERSION_haddock(x,y,z) 0
  #endif
  
  #if !(defined(__HADDOCK_VERSION__)) || MIN_TOOL_VERSION_haddock(2,14,0)
    , Proxy(..) -- hidden from old Haddock versions, because it triggers an internal error
  #endif
    ) where
  
  import Data.Proxy (Proxy(..))
  
  import Generics.SOP.BasicFunctors
  import Generics.SOP.Classes
  import Generics.SOP.Constraint
  import Generics.SOP.Instances ()
  import Generics.SOP.Metadata
  import Generics.SOP.NP
  import Generics.SOP.NS
  import Generics.SOP.Universe
  import Generics.SOP.Sing
  
  -- $setup
  --
  -- >>> :set -XDeriveGeneric
  -- >>> import qualified GHC.Generics as GHC
  -- >>> import Generics.SOP
  -- >>> import Control.DeepSeq
  -- >>> data B a = F | G a Char Bool deriving (Show, GHC.Generic)
  -- >>> data A   = C Bool | D A Int | E (B ()) deriving (Show, GHC.Generic)
  -- >>> instance Generic A     -- empty
  -- >>> instance Generic (B a) -- empty
  --
  -- >>> let grnf = rnf . hcollapse . hcmap (Proxy :: Proxy NFData) (\ (I x) -> K (rnf x)) . from
  