cassette-0.2.0: src/Control/Lens.hs
{-# LANGUAGE RankNTypes #-}
-- | Minimal re-implementation of just enough of lens, in order to avoid the
-- dependency. This is for INTERNAL USE ONLY. In downstream code, use lens or
-- any optics library.
module Control.Lens
( -- * Lenses
Lens
, view
-- * Isomorphisms
, Iso
, iso
, from
-- * Prisms
, Prism
, preview
, review
) where
import Data.Bifunctor (first)
import Data.Coerce (coerce)
import Data.Functor.Const (Const(..))
import Data.Functor.Identity (Identity(..))
import Data.Profunctor (Profunctor(..))
import Data.Profunctor.Unsafe ((#.))
import Data.Profunctor.Choice (Choice(..))
type Lens s t a b = forall f. (Functor f) => (a -> f b) -> s -> f t
type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)
type Prism s t a b = forall p f. (Choice p, Applicative f) => p a (f b) -> p s (f t)
view :: Lens s t a b -> s -> a
view l s = getConst (l Const s)
data Market a b s t = Market (b -> t) (s -> Either t a)
instance Profunctor (Market a b) where
dimap f g (Market bt seta) = Market (g . bt) (first g . seta . f)
instance Choice (Market a b) where
right' (Market bt seta) = Market bt' seta'
where
bt' b = Right (bt b)
seta' (Left c) = Left (Left c)
seta' (Right s) = either (Left . Right) Right (seta s)
withPrism
:: Prism s t a b
-> ((b -> t) -> (s -> Either t a) -> r)
-> r
withPrism k f = case coerce (k (Market Identity Right)) of
Market bt seta -> f bt seta
review :: Prism s t a b -> b -> t
review p = withPrism p $ \build _ -> build
preview :: Prism s t a b -> s -> Maybe a
preview p = withPrism p $ \_ match -> either (const Nothing) Just . match
data Exchange a b s t = Exchange (s -> a) (b -> t)
instance Profunctor (Exchange a b) where
dimap f g (Exchange sa bt) = Exchange (sa . f) (g . bt)
iso :: (s -> a) -> (b -> t) -> Iso s t a b
iso sa bt = dimap sa (fmap bt)
withIso :: Iso s t a b -> ((s -> a) -> (b -> t) -> r) -> r
withIso l k = case l (Exchange id Identity) of
Exchange sa bt -> k sa (runIdentity #. bt)
from :: Iso s t a b -> Iso b a t s
from l = withIso l $ \sa bt -> iso bt sa