optics-core-0.2: src/Optics/Internal/Bi.hs
{-# OPTIONS_HADDOCK not-home #-}
-- | Classes for co- and contravariant bifunctors.
--
-- This module is intended for internal use only, and may change without warning
-- in subsequent releases.
module Optics.Internal.Bi where
import Data.Coerce
import Data.Void
import Data.Profunctor.Indexed
-- | Class for (covariant) bifunctors.
class Bifunctor p where
bimap :: (a -> b) -> (c -> d) -> p i a c -> p i b d
first :: (a -> b) -> p i a c -> p i b c
second :: (c -> d) -> p i a c -> p i a d
instance Bifunctor Tagged where
bimap _f g = Tagged #. g .# unTagged
first _f = coerce
second g = Tagged #. g .# unTagged
{-# INLINE bimap #-}
{-# INLINE first #-}
{-# INLINE second #-}
-- | Class for contravariant bifunctors.
class Bicontravariant p where
contrabimap :: (b -> a) -> (d -> c) -> p i a c -> p i b d
contrafirst :: (b -> a) -> p i a c -> p i b c
contrasecond :: (c -> b) -> p i a b -> p i a c
instance Bicontravariant (Forget r) where
contrabimap f _g (Forget k) = Forget (k . f)
contrafirst f (Forget k) = Forget (k . f)
contrasecond _g (Forget k) = Forget k
{-# INLINE contrabimap #-}
{-# INLINE contrafirst #-}
{-# INLINE contrasecond #-}
instance Bicontravariant (ForgetM r) where
contrabimap f _g (ForgetM k) = ForgetM (k . f)
contrafirst f (ForgetM k) = ForgetM (k . f)
contrasecond _g (ForgetM k) = ForgetM k
{-# INLINE contrabimap #-}
{-# INLINE contrafirst #-}
{-# INLINE contrasecond #-}
instance Bicontravariant (IxForget r) where
contrabimap f _g (IxForget k) = IxForget (\i -> k i . f)
contrafirst f (IxForget k) = IxForget (\i -> k i . f)
contrasecond _g (IxForget k) = IxForget k
{-# INLINE contrabimap #-}
{-# INLINE contrafirst #-}
{-# INLINE contrasecond #-}
instance Bicontravariant (IxForgetM r) where
contrabimap f _g (IxForgetM k) = IxForgetM (\i -> k i . f)
contrafirst f (IxForgetM k) = IxForgetM (\i -> k i . f)
contrasecond _g (IxForgetM k) = IxForgetM k
{-# INLINE contrabimap #-}
{-# INLINE contrafirst #-}
{-# INLINE contrasecond #-}
----------------------------------------
-- | If @p@ is a 'Profunctor' and a 'Bifunctor' then its left parameter must be
-- phantom.
lphantom :: (Profunctor p, Bifunctor p) => p i a c -> p i b c
lphantom = first absurd . lmap absurd
{-# INLINE lphantom #-}
-- | If @p@ is a 'Profunctor' and 'Bicontravariant' then its right parameter
-- must be phantom.
rphantom :: (Profunctor p, Bicontravariant p) => p i c a -> p i c b
rphantom = rmap absurd . contrasecond absurd
{-# INLINE rphantom #-}