{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
#ifdef TRUSTWORTHY
{-# LANGUAGE Trustworthy #-}
#endif
module Control.Lens.Prism
(
Prism, Prism'
, APrism, APrism'
, prism
, prism'
, withPrism
, clonePrism
, outside
, aside
, without
, below
, isn't
, matching
, _Left
, _Right
, _Just
, _Nothing
, _Void
, _Show
, only
, nearly
, Choice(..)
) where
import Control.Applicative
import Control.Lens.Internal.Prism
import Control.Lens.Lens
import Control.Lens.Review
import Control.Lens.Type
import Control.Monad
import Data.Functor.Identity
import Data.Profunctor
import Data.Profunctor.Rep
import Data.Traversable
import Data.Void
#ifndef SAFE
import Unsafe.Coerce
#else
import Data.Profunctor.Unsafe
#endif
{-# ANN module "HLint: ignore Use camelCase" #-}
type APrism s t a b = Market a b a (Identity b) -> Market a b s (Identity t)
type APrism' s a = APrism s s a a
withPrism :: APrism s t a b -> ((b -> t) -> (s -> Either t a) -> r) -> r
#ifdef SAFE
withPrism k f = case k (Market Identity Right) of
Market bt seta -> f (runIdentity #. bt) (either (Left . runIdentity) Right . seta)
#else
withPrism k f = case unsafeCoerce (k (Market Identity Right)) of
Market bt seta -> f bt seta
#endif
{-# INLINE withPrism #-}
clonePrism :: APrism s t a b -> Prism s t a b
clonePrism k = withPrism k prism
{-# INLINE clonePrism #-}
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' #-}
outside :: Representable p => APrism s t a b -> Lens (p t r) (p s r) (p b r) (p a r)
outside k = withPrism k $ \bt seta f ft ->
f (lmap bt ft) <&> \fa -> tabulate $ either (rep ft) (rep fa) . seta
{-# INLINE outside #-}
without :: APrism s t a b
-> APrism u v c d
-> Prism (Either s u) (Either t v) (Either a c) (Either b d)
without k =
withPrism k $ \bt seta k' ->
withPrism k' $ \dv uevc ->
prism (bimap bt dv) $ \su ->
case su of
Left s -> bimap Left Left (seta s)
Right u -> bimap Right Right (uevc u)
{-# INLINE without #-}
aside :: APrism s t a b -> Prism (e, s) (e, t) (e, a) (e, b)
aside k =
withPrism k $ \bt seta ->
prism (fmap bt) $ \(e,s) ->
case seta s of
Left t -> Left (e,t)
Right a -> Right (e,a)
{-# INLINE aside #-}
below :: Traversable f => APrism' s a -> Prism' (f s) (f a)
below k =
withPrism k $ \bt seta ->
prism (fmap bt) $ \s ->
case traverse seta s of
Left _ -> Left s
Right t -> Right t
{-# INLINE below #-}
isn't :: APrism s t a b -> s -> Bool
isn't k s =
case matching k s of
Left _ -> True
Right _ -> False
{-# INLINE isn't #-}
matching :: APrism s t a b -> s -> Either t a
matching k = withPrism k $ \_ seta -> seta
{-# INLINE matching #-}
_Left :: Prism (Either a c) (Either b c) a b
_Left = prism Left $ either Right (Left . Right)
{-# INLINE _Left #-}
_Right :: Prism (Either c a) (Either c b) a b
_Right = prism Right $ either (Left . Left) Right
{-# INLINE _Right #-}
_Just :: Prism (Maybe a) (Maybe b) a b
_Just = prism Just $ maybe (Left Nothing) Right
{-# INLINE _Just #-}
_Nothing :: Prism' (Maybe a) ()
_Nothing = prism' (const Nothing) $ maybe (Just ()) (const Nothing)
{-# INLINE _Nothing #-}
_Void :: Prism s s a Void
_Void = prism absurd Left
{-# INLINE _Void #-}
only :: Eq a => a -> Prism' a ()
only a = prism' (\() -> a) $ guard . (a ==)
{-# INLINE only #-}
nearly :: a -> (a -> Bool) -> Prism' a ()
nearly a p = prism' (\() -> a) $ guard . p
{-# INLINE nearly #-}
_Show :: (Read a, Show a) => Prism' String a
_Show = prism show $ \s -> case reads s of
[(a,"")] -> Right a
_ -> Left s
{-# INLINE _Show #-}