{-# LANGUAGE RankNTypes #-}
module Lens.Labels.Prism
( Prism
, Prism'
, AReview
, (#)
, prism
, prism'
, _Left
, _Right
, _Just
, _Nothing
) where
import Data.Tagged (Tagged (..))
import Data.Functor.Identity (Identity (..))
import Data.Profunctor (dimap)
import Data.Profunctor.Choice
import Data.Profunctor.Unsafe ((#.), (.#))
type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
type Prism' s a = Prism s s a a
type Optic p f s t a b = p a (f b) -> p s (f t)
type Optic' p f s a = Optic p f s s a a
type AReview t b = Optic' Tagged Identity t b
( # ) :: AReview t b -> b -> t
( # ) p = runIdentity #. unTagged #. p .# Tagged .# Identity
infixr 8 #
prism :: (b -> t) -> (s -> Either t a) -> Prism s t a b
prism bt seta = dimap seta (either pure (fmap bt)) . right'
{-# INLINE prism #-}
prism' :: (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' bs sma = prism bs (\s -> maybe (Left s) Right (sma s))
{-# INLINE prism' #-}
_Left :: Prism (Either a c) (Either b c) a b
_Left = prism Left $ either Right (Left . Right)
_Right :: Prism (Either c a) (Either c b) a b
_Right = prism Right $ either (Left . Left) Right
_Just :: Prism (Maybe a) (Maybe b) a b
_Just = prism Just $ maybe (Left Nothing) Right
_Nothing :: Prism' (Maybe a) ()
_Nothing = prism' (const Nothing) $ maybe (Just ()) (const Nothing)