packages feed

microlens-pro-0.1.0: src/Lens/Micro/Pro/Internal.hs

{-|
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