content: {-|
  Module      : Lens.Micro.Pro.Internal
  Copyright   : (C) 2013-2016 Edward Kmett, 2018 Monadfix
  License     : BSD-style (see the file LICENSE)
  
  Definitions used internally by microlens. If you're going to use these, only
  define instances for your own types, and don't export an API using these!
  -}
  {-# LANGUAGE FunctionalDependencies #-}
  module Lens.Micro.Pro.Internal
      ( Strict(strict, lazy)
  
      , IsText(packed, unpacked)
  
      , Exchange(..), Exchange'
      , Market(..), Market'
  
      , Iso, Iso'
      , Prism, Prism'
      )
      where
  --------------------------------------------------------------------------------
  import Lens.Micro.Pro.Type
  import Data.Coerce
  import Data.Profunctor
  import Data.Profunctor.Unsafe
  --------------------------------------------------------------------------------
  
  class Strict lazy strict | lazy -> strict, strict -> lazy where
      strict :: Iso' lazy   strict
      lazy   :: Iso' strict lazy
  
  {- | This type is used internally to provide efficient access
  to the two inverse functions behind an 'Iso'.
  -}
  
  data Exchange a b s t = Exchange (s -> a) (b -> t)
  
  type Exchange' a s = Exchange a a s s
  
  instance Functor (Exchange a b s) where
      fmap f (Exchange sa bt) = Exchange sa (f . bt)
      {-# INLINE fmap #-}
  
  instance Profunctor (Exchange a b) where
      dimap f g (Exchange sa bt) = Exchange (sa . f) (g . bt)
      lmap f (Exchange sa bt) = Exchange (sa . f) bt
      rmap f (Exchange sa bt) = Exchange sa (f . bt)
  
      {-# INLINE dimap #-}
      {-# INLINE lmap #-}
      {-# INLINE rmap #-}
  
      (#.) _ = coerce
      (.#) p _ = coerce p
  
      {-# INLINE (#.) #-}
      {-# INLINE (.#) #-}
  
  {- | This type is used internally by the Prism code to provide efficient access
  to the two parts of a Prism, i.e. a constructor and a selector — see:
  'Lens.Micro.Pro.prism'.
  -}
  data Market a b s t = Market (b -> t) (s -> Either t a)
  
  instance Functor (Market a b s) where
    fmap f (Market bt seta) = Market (f . bt) (either (Left . f) Right . seta)
    {-# INLINE fmap #-}
  
  instance Profunctor (Market a b) where
      dimap f g (Market bt seta) =
          Market (g . bt) (either (Left . g) Right . seta . f)
  
      lmap f (Market bt seta) = Market bt (seta . f)
      rmap f (Market bt seta) = Market (f . bt) (either (Left . f) Right . seta)
  
      {-# INLINE rmap #-}
      {-# INLINE lmap #-}
      {-# INLINE dimap #-}
  
      (#.) _ = coerce
      (.#) p _ = coerce p
  
      {-# INLINE (#.) #-}
      {-# INLINE (.#) #-}
  
  instance Choice (Market a b) where
      left' (Market bt seta) = Market (Left . bt) $ \sc -> case sc of
          Left s -> case seta s of
              Left t -> Left (Left t)
              Right a -> Right a
          Right c -> Left (Right c)
  
      right' (Market bt seta) = Market (Right . bt) $ \cs -> case cs of
          Left c -> Left (Left c)
          Right s -> case seta s of
              Left t -> Left (Right t)
              Right a -> Right a
  
      {-# INLINE right' #-}
      {-# INLINE left' #-}
  
  type Market' a s = Market a a s s
  
  class IsText t where
  
      -- | 'packed' lets you convert between 'String' and @Text@ (strict or lazy).
      -- It can be used as a replacement for @pack@ or as a way to modify some
      -- 'String' if you have a function like @Text -> Text@.
  
      packed   :: Iso' String t
  
      -- | 'unpacked' is like 'packed' but works in the opposite direction.
  
      unpacked :: Iso' t String
  
  