    {-# LANGUAGE CPP #-}
    -- |
    -- Module: Optics.Optic
    -- Description: Common abstraction for all kinds of optics.
    --
    -- This module provides core definitions:
    --
    -- * an opaque 'Optic' type, which is parameterised over a type representing an
    --   optic kind (instantiated with tag types such as 'A_Lens');
    --
    -- * the optic composition operator ('%');
    --
    -- * the subtyping relation 'Is' with an accompanying 'castOptic' function to
    --   convert an optic kind;
    --
    -- * the 'JoinKinds' class used to find the optic kind resulting from a
    --   composition.
    --
    -- Each optic kind is identified by a "tag type" (such as 'A_Lens'), which is an
    -- empty data type.  The type of the actual optics (such as 'Optics.Lens.Lens')
    -- is obtained by applying 'Optic' to the tag type.
    --
    -- See the @Optics@ module in the main @optics@ package for overview
    -- documentation.
    --
    module Optics.Optic
      ( OpticKind
      , Optic
      , Optic'

      -- * Subtyping
      , castOptic
      , Is
      , JoinKinds

      -- * Composition
      -- | The usual operator for composing optics is ('%'), which allows different
      -- optic kinds to be composed, automatically calculating the resulting optic
      -- kind using 'JoinKinds'.
      --
      -- The ('.') function composition operator cannot be used to compose optics,
      -- because /optics are not functions/.  The ('Control.Category..') operator
      -- from "Control.Category" cannot be used either, because it would not support
      -- type-changing optics or composing optics of different kinds.
      , (%)
      , (%%)
      , (%&)

      -- * Monoid structures
      -- | 'Optics.Fold.Fold'-like optics admit various monoid structures (e.g. see
      -- "Optics.Fold#monoids").  There is no 'Semigroup' or 'Monoid' instance for
      -- 'Optic', however, because there is not a unique choice of monoid to use,
      -- and the ('<>') operator could not be used to combine optics of different
      -- kinds.

      -- * Indexed optics
      -- | See the "Indexed optics" section of the overview documentation in the
      -- @Optics@ module of the main @optics@ package for more details on indexed
      -- optics.
      , IxList
      , NoIx
      , WithIx
      , AppendIndices
      , NonEmptyIndices
      , HasSingleIndex
      , AcceptsEmptyIndices
      , Curry
      , CurryCompose(..)

        -- * Base re-exports
      , (&)
      , (<&>)
      )
      where

    import Data.Function

    import Optics.Internal.Indexed
    import Optics.Internal.Optic

    #if MIN_VERSION_base(4,11,0)
    import Data.Functor ((<&>))
    #else
    -- | Infix flipped 'fmap'.
    --
    -- @
    -- ('<&>') = 'flip' 'fmap'
    -- @
    (<&>) :: Functor f => f a -> (a -> b) -> f b
    as <&> f = f <$> as
    {-# INLINE (<&>) #-}
    infixl 1 <&>
    #endif