content: {-# LANGUAGE Trustworthy #-}
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Data.Extensible.Internal.Rig
  -- Copyright   :  (c) Fumiaki Kinoshita 2018
  -- License     :  BSD3
  --
  -- Maintainer  :  Fumiaki Kinoshita <fumiexcel@gmail.com>
  --
  -- Re-implementation of lens combinators
  ------------------------------------------------------------------------
  module Data.Extensible.Internal.Rig (
    Optic
    , Optic'
    , view
    , views
    , over
    , withIso
    , Exchange(..)
    , review
    )
  where
  import Control.Applicative
  import Data.Profunctor
  import Data.Functor.Identity
  import Data.Tagged
  import Data.Coerce
  
  type Optic p f s t a b = p a (f b) -> p s (f t)
  type Optic' p f s a = p a (f a) -> p s (f s)
  
  -- | @'view' :: Getter s a -> s -> a@
  view :: Optic' (->) (Const a) s a -> s -> a
  view l = views l id
  {-# INLINE view #-}
  
  -- | @'views' :: Getter s a -> (a -> r) -> (s -> r)@
  views :: Optic' (->) (Const r) s a -> (a -> r) -> s -> r
  views = coerce
  {-# INLINE views #-}
  
  -- | @'over' :: Setter s t a b -> (a -> b) -> (s -> t)@
  over :: Optic (->) Identity s t a b -> (a -> b) -> s -> t
  over = coerce
  {-# INLINE over #-}
  
  -- | Reifies the structure of 'Iso's
  data Exchange a b s t = Exchange (s -> a) (b -> t)
  
  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)
    {-# INLINE dimap #-}
  
  -- | Recover tho functions from an Iso/
  withIso :: Optic (Exchange a b) Identity s t a b -> ((s -> a) -> (b -> t) -> r) -> r
  withIso l r = case l (Exchange id Identity) of
    Exchange f g -> r f (coerce g)
  {-# INLINE withIso #-}
  
  -- | @'review' :: AReview s a -> a -> s@
  review :: Optic' Tagged Identity s a -> a -> s
  review = coerce
  {-# INLINE review #-}
  