# 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

 |
 Module: Optics.Optic
 Description: Common abstraction for all kinds of optics.

 This module provides core definitions:

   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')

 documentation.

 * Subtyping
 * Composition
 | The usual operator for composing optics is ('%'), which allows different
 optic kinds to be composed, automatically calculating the resulting optic

 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
 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.
 * Base re-exports
 | Infix flipped 'fmap'.

 @
 ('<&>') = 'flip' 'fmap'
 @
# INLINE (<&>) #
# LANGUAGE CPP #
  * an opaque ' Optic ' type , which is parameterised over a type representing an
  is obtained by applying ' Optic ' to the tag type .
  See the @Optics@ module in the main @optics@ package for overview
module Optics.Optic
  ( OpticKind
  , Optic
  , Optic'

  , castOptic
  , Is
  , JoinKinds

  kind using ' JoinKinds ' .
  , (%)
  , (%%)
  , (%&)

  ' Optic ' , however , because there is not a unique choice of monoid to use ,

  , IxList
  , NoIx
  , WithIx
  , AppendIndices
  , NonEmptyIndices
  , HasSingleIndex
  , AcceptsEmptyIndices
  , Curry
  , CurryCompose(..)

  , (&)
  , (<&>)
  )
  where

import Data.Function

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

#if MIN_VERSION_base(4,11,0)
import Data.Functor ((<&>))
#else
(<&>) :: Functor f => f a -> (a -> b) -> f b
as <&> f = f <$> as
infixl 1 <&>
#endif
