module Control.Lens.SemiIso (
SemiIso,
SemiIso',
ASemiIso,
ASemiIso',
pattern SemiIso,
semiIso,
cloneSemiIso,
ReifiedSemiIso'(..),
reifySemiIso,
apply,
unapply,
withSemiIso,
viewSemiIso,
unit,
swapped,
associated,
morphed,
constant,
exact,
bifiltered,
alwaysFailing,
_Negative,
rev,
prod,
elimFirst,
elimSecond,
attempt,
attemptAp,
attemptUn,
attempt_,
attemptAp_,
attemptUn_,
bifoldr,
bifoldr1,
bifoldl,
bifoldl1,
bifoldr_,
bifoldr1_,
bifoldl_,
bifoldl1_
) where
import Prelude hiding (id, (.))
import Control.Arrow
import Control.Category
import Control.Lens.Internal.SemiIso
import Control.Lens.Iso
import Data.Foldable
import Data.Functor.Identity
import Data.Profunctor.Exposed
import Data.Traversable
import Data.Tuple.Morph
type SemiIso s t a b = forall p f. (Exposed (Either String) p, Traversable f)
=> p a (f b) -> p s (f t)
type SemiIso' s a = SemiIso s s a a
type ASemiIso s t a b = Retail a b a (Identity b) -> Retail a b s (Identity t)
type ASemiIso' s a = ASemiIso s s a a
pattern SemiIso sa bt <- (viewSemiIso -> (sa, bt))
newtype ReifiedSemiIso' s a = ReifiedSemiIso' { runSemiIso :: SemiIso' s a }
instance Category ReifiedSemiIso' where
id = ReifiedSemiIso' id
ReifiedSemiIso' f . ReifiedSemiIso' g = ReifiedSemiIso' (g . f)
instance Arrow ReifiedSemiIso' where
arr = undefined
(&&&) = undefined
first (ReifiedSemiIso' ai) = withSemiIso ai $ \f g ->
ReifiedSemiIso' $ cloneSemiIso $
semiIso (runKleisli $ first $ Kleisli f)
(runKleisli $ first $ Kleisli g)
second (ReifiedSemiIso' ai) = withSemiIso ai $ \f g ->
ReifiedSemiIso' $ cloneSemiIso $
semiIso (runKleisli $ second $ Kleisli f)
(runKleisli $ second $ Kleisli g)
ReifiedSemiIso' ai *** ReifiedSemiIso' ai' = ReifiedSemiIso' $
withSemiIso ai $ \f g -> withSemiIso ai' $ \f' g' ->
semiIso (runKleisli $ Kleisli f *** Kleisli f')
(runKleisli $ Kleisli g *** Kleisli g')
semiIso :: (s -> Either String a) -> (b -> Either String t) -> SemiIso s t a b
semiIso sa bt = merge . dimap sa (sequenceA . fmap bt) . expose
cloneSemiIso :: ASemiIso s t a b -> SemiIso s t a b
cloneSemiIso (SemiIso sa bt) = semiIso sa bt
apply :: ASemiIso s t a b -> s -> Either String a
apply (SemiIso sa _) = sa
unapply :: ASemiIso s t a b -> b -> Either String t
unapply (SemiIso _ bt) = bt
withSemiIso :: ASemiIso s t a b
-> ((s -> Either String a) -> (b -> Either String t) -> r)
-> r
withSemiIso ai k = case ai (Retail Right (Right . Identity)) of
Retail sa bt -> k sa (rmap (runIdentity . sequenceA) bt)
viewSemiIso :: ASemiIso s t a b -> (s -> Either String a, b -> Either String t)
viewSemiIso ai = withSemiIso ai (,)
reifySemiIso :: ASemiIso' s a -> ReifiedSemiIso' s a
reifySemiIso ai = ReifiedSemiIso' $ cloneSemiIso ai
unit :: Iso' a (a, ())
unit = iso (, ()) fst
associated :: Iso' (a, (b, c)) ((a, b), c)
associated = iso (\(a, (b, c)) -> ((a, b), c)) (\((a, b), c) -> (a, (b, c)))
morphed :: (HFoldable a, HUnfoldable a, HFoldable b, HUnfoldable b, Rep a ~ Rep b)
=> Iso' a b
morphed = iso morph morph
constant :: a -> SemiIso' () a
constant x = semiIso (\_ -> Right x) (\_ -> Right ())
exact :: Eq a => a -> SemiIso' a ()
exact x = semiIso f g
where
f y | x == y = Right ()
| otherwise = Left "exact: not equal"
g _ = Right x
bifiltered :: (a -> Bool) -> SemiIso' a a
bifiltered p = semiIso check check
where check x | p x = Right x
| otherwise = Left "bifiltered: predicate failed"
alwaysFailing :: String -> SemiIso s t a b
alwaysFailing msg = semiIso (\_ -> Left msg) (\_ -> Left msg)
_Negative :: Real a => SemiIso' a a
_Negative = semiIso f g
where
f x | x < 0 = Right (x)
| otherwise = Left "_Negative: apply expected a negative number"
g x | x >= 0 = Right (x)
| otherwise = Left "_Negative: unapply expected a positive number"
rev :: ASemiIso s t a b -> SemiIso b a t s
rev ai = withSemiIso ai $ \l r -> semiIso r l
prod :: ASemiIso' s a -> ASemiIso' t b -> SemiIso' (s, t) (a, b)
prod a b = runSemiIso (reifySemiIso a *** reifySemiIso b)
elimFirst :: ASemiIso' s () -> SemiIso' (s, t) t
elimFirst ai = swapped . elimSecond ai
elimSecond :: ASemiIso' s () -> SemiIso' (t, s) t
elimSecond ai = runSemiIso (id *** reifySemiIso ai) . rev unit
attempt :: ASemiIso s t a b -> SemiIso s (Either String t) (Either String a) b
attempt = attemptAp . attemptUn
attemptAp :: ASemiIso s t a b -> SemiIso s t (Either String a) b
attemptAp (SemiIso sa bt) = semiIso (Right . sa) bt
attemptUn :: ASemiIso s t a b -> SemiIso s (Either String t) a b
attemptUn (SemiIso sa bt) = semiIso sa (Right . bt)
discard :: Either a b -> Maybe b
discard = either (const Nothing) Just
attempt_ :: ASemiIso s t a b -> SemiIso s (Maybe t) (Maybe a) b
attempt_ ai = rmap (fmap discard) . attempt ai . lmap discard
attemptAp_ :: ASemiIso s t a b -> SemiIso s t (Maybe a) b
attemptAp_ ai = attemptAp ai . lmap discard
attemptUn_ :: ASemiIso s t a b -> SemiIso s (Maybe t) a b
attemptUn_ ai = rmap (fmap discard) . attemptUn ai
foldlM1 :: Monad m => (a -> a -> m a) -> [a] -> m a
foldlM1 f (x:xs) = foldlM f x xs
foldlM1 _ [] = fail "foldlM1: empty list"
foldrM1 :: Monad m => (a -> a -> m a) -> [a] -> m a
foldrM1 _ [x] = return x
foldrM1 f (x:xs) = foldrM1 f xs >>= f x
foldrM1 _ [] = fail "foldrM1: empty list"
unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m (a, [b])
unfoldrM f a = do
r <- f a
case r of
Just (b, new_a) -> do
(final_a, bs) <- unfoldrM f new_a
return (final_a, b : bs)
Nothing -> return (a, [])
unfoldrM1 :: Monad m => (a -> m (Maybe (a, a))) -> a -> m [a]
unfoldrM1 f a = do
r <- f a
case r of
Just (b, new_a) -> do
bs <- unfoldrM1 f new_a
return (b : bs)
Nothing -> return [a]
unfoldlM :: Monad m => (a -> m (Maybe (a, b))) -> a -> m (a, [b])
unfoldlM f a0 = go a0 []
where
go a bs = do
r <- f a
case r of
Just (new_a, b) -> go new_a (b : bs)
Nothing -> return (a, bs)
unfoldlM1 :: Monad m => (a -> m (Maybe (a, a))) -> a -> m [a]
unfoldlM1 f a0 = go a0 []
where
go a bs = do
r <- f a
case r of
Just (new_a, b) -> go new_a (b : bs)
Nothing -> return (a : bs)
bifoldr :: ASemiIso' a (b, a) -> SemiIso' a (a, [b])
bifoldr = bifoldr_ . attemptAp_
bifoldr1 :: ASemiIso' a (a, a) -> SemiIso' a [a]
bifoldr1 = bifoldr1_ . attemptAp_
bifoldl :: ASemiIso' a (a, b) -> SemiIso' a (a, [b])
bifoldl = bifoldl_ . attemptAp_
bifoldl1 :: ASemiIso' a (a, a) -> SemiIso' a [a]
bifoldl1 = bifoldl1_ . attemptAp_
bifoldr_ :: ASemiIso a a (Maybe (b, a)) (b, a) -> SemiIso' a (a, [b])
bifoldr_ ai = semiIso (uf ai) (f ai)
where
f = uncurry . foldrM . curry . unapply
uf = unfoldrM . apply
bifoldr1_ :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
bifoldr1_ ai = semiIso (uf ai) (f ai)
where
f = foldrM1 . curry . unapply
uf = unfoldrM1 . apply
bifoldl_ :: ASemiIso a a (Maybe (a, b)) (a, b) -> SemiIso' a (a, [b])
bifoldl_ ai = semiIso (uf ai) (f ai)
where
f = uncurry . foldlM . curry . unapply
uf = unfoldlM . apply
bifoldl1_ :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
bifoldl1_ ai = semiIso (uf ai) (f ai)
where
f = foldlM1 . curry . unapply
uf = unfoldlM1 . apply