{-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE MultiParamTypeClasses #-} {- | Module : Control.Lens.Internal.SemiIso Description : Internals of a SemiIso. Copyright : (c) Paweł Nowak License : MIT Maintainer : Paweł Nowak Stability : experimental -} module Control.Lens.Internal.SemiIso where import Control.Monad import Data.Profunctor import Data.Profunctor.Exposed -- | Type used internally to access 'SemiIso'. -- -- Continues the naming tradition of @lens@. data Retail s t a b = Retail (a -> Either String s) (t -> Either String b) instance Profunctor (Retail s t) where lmap f (Retail l r) = Retail (l . f) r rmap f (Retail l r) = Retail l (fmap f . r) instance Choice (Retail s t) where left' (Retail as st) = Retail (either as (\_ -> Left "semi-iso failed")) (fmap Left . st) right' (Retail as st) = Retail (either (\_ -> Left "semi-iso failed") as) (fmap Right . st) -- Proof of 'Exposed' laws: -- -- > merge . rmap return = id -- -- merge . rmap return $ Retail l r = -- merge $ Retail l (return . r) = -- Retail l (join . return . r) = -- Retail l r -- -- > lmap return . expose = id -- -- lmap return . expose $ Retail l r = -- lmap return $ Retail (>>= l) r = -- Retail ((>>= l) . return) r = -- Retail (join . fmap l . return) r = -- Retail (join . return . l) r = -- Retail l r -- -- > rmap (>>= f) = merge . rmap (fmap f) -- -- rmap (>>= f) $ Retail l r = -- Retail l ((>>= f) . r) = -- Retail l (join . fmap f . r) = -- merge $ Retail l (fmap f . r) = -- merge . rmap (fmap f) $ Retail l r -- -- > lmap (fmap f) . expose = expose . lmap f -- -- lmap (fmap f) . expose $ Retail l r = -- lmap (fmap f) $ Retail (>>= l) r = -- Retail ((>>= l) . fmap f) r = -- Retail (>>= (l . f)) r = -- expose $ Retail (l . f) r = -- expose . lmap f $ Retail l r instance Exposed (Either String) (Retail s t) where expose (Retail l r) = Retail (>>= l) r merge (Retail l r) = Retail l (join . r)