semi-iso 0.3.0.0 → 0.4.0.0
raw patch · 3 files changed
+252/−84 lines, 3 filesdep +tuple-morphPVP ok
version bump matches the API change (PVP)
Dependencies added: tuple-morph
API changes (from Hackage documentation)
- Control.Lens.SemiIso: foldlM1 :: Monad m => (a -> a -> m a) -> [a] -> m a
- Control.Lens.SemiIso: foldrM1 :: Monad m => (a -> a -> m a) -> [a] -> m a
- Control.Lens.SemiIso: fromSemi :: ASemiIso s t a b -> SemiIso b a t s
- Control.Lens.SemiIso: unfoldlM :: Monad m => (a -> m (Maybe (a, b))) -> a -> m (a, [b])
- Control.Lens.SemiIso: unfoldlM1 :: Monad m => (a -> m (Maybe (a, a))) -> a -> m [a]
- Control.Lens.SemiIso: unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m (a, [b])
- Control.Lens.SemiIso: unfoldrM1 :: Monad m => (a -> m (Maybe (a, a))) -> a -> m [a]
+ Control.Lens.SemiIso: _Negative :: Real a => SemiIso' a a
+ Control.Lens.SemiIso: bifiltered :: (a -> Bool) -> SemiIso' a a
+ Control.Lens.SemiIso: bifoldl1_ :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
+ Control.Lens.SemiIso: bifoldl_ :: ASemiIso a a (Maybe (a, b)) (a, b) -> SemiIso' a (a, [b])
+ Control.Lens.SemiIso: bifoldr1_ :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
+ Control.Lens.SemiIso: bifoldr_ :: ASemiIso a a (Maybe (b, a)) (b, a) -> SemiIso' a (a, [b])
+ Control.Lens.SemiIso: elimFirst :: ASemiIso s' t' () () -> SemiIso (s', t) (t', t) t t
+ Control.Lens.SemiIso: elimSecond :: ASemiIso s' t' () () -> SemiIso (t, s') (t, t') t t
+ Control.Lens.SemiIso: morphed :: (HFoldable a, HUnfoldable a, HFoldable b, HUnfoldable b, Rep a ~ Rep b) => Iso' a b
+ Control.Lens.SemiIso: prod :: ASemiIso s t a b -> ASemiIso s' t' a' b' -> SemiIso (s, s') (t, t') (a, a') (b, b')
+ Control.Lens.SemiIso: rev :: ASemiIso s t a b -> SemiIso b a t s
+ Control.Lens.SemiIso: viewSemiIso :: ASemiIso s t a b -> (s -> Either String a, b -> Either String t)
+ Data.SemiIsoFunctor: (/$~) :: (SemiIsoFunctor f, HFoldable b', HFoldable b, HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b) => ASemiIso' a b' -> f b -> f a
+ Data.SemiIsoFunctor: (//=) :: SemiIsoMonad m => m a -> (a -> m b) -> m (a, b)
+ Data.SemiIsoFunctor: (=//) :: SemiIsoMonad m => (b -> m a) -> m b -> m (a, b)
+ Data.SemiIsoFunctor: (=//=) :: SemiIsoFix m => (a -> m b) -> (b -> m a) -> m (a, b)
+ Data.SemiIsoFunctor: (~$/) :: (SemiIsoFunctor f, HFoldable a', HFoldable a, HUnfoldable a', HUnfoldable a, Rep a' ~ Rep a) => ASemiIso' a' b -> f b -> f a
+ Data.SemiIsoFunctor: (~$~) :: (SemiIsoFunctor f, HFoldable a, HUnfoldable a, HFoldable b, HUnfoldable b, HFoldable b', HUnfoldable b', Rep b' ~ Rep b, Rep b' ~ Rep a) => ASemiIso b' b' b' b' -> f b -> f a
+ Data.SemiIsoFunctor: class SemiIsoMonad m => SemiIsoFix m where sifix f = dup /$/ (f =//= f) where dup = semiIso (\ a -> Right (a, a)) (Right . fst) f =//= g = sifix (\ (a, b) -> g b /*/ f a)
+ Data.SemiIsoFunctor: class SemiIsoApply m => SemiIsoMonad m where m //= f = swapped /$/ (f =// m) f =// m = swapped /$/ (m //= f)
+ Data.SemiIsoFunctor: sifix :: SemiIsoFix m => (a -> m a) -> m a
+ Data.SemiIsoFunctor: sipureCo :: SemiIsoApply f => ASemiIso' () a -> f a
+ Data.SemiIsoFunctor: siunit :: SemiIsoApply f => f ()
- Control.Lens.SemiIso: bifoldl :: ASemiIso a a (Maybe (a, b)) (a, b) -> SemiIso' a (a, [b])
+ Control.Lens.SemiIso: bifoldl :: ASemiIso' a (a, b) -> SemiIso' a (a, [b])
- Control.Lens.SemiIso: bifoldl1 :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
+ Control.Lens.SemiIso: bifoldl1 :: ASemiIso' a (a, a) -> SemiIso' a [a]
- Control.Lens.SemiIso: bifoldr :: ASemiIso a a (Maybe (b, a)) (b, a) -> SemiIso' a (a, [b])
+ Control.Lens.SemiIso: bifoldr :: ASemiIso' a (b, a) -> SemiIso' a (a, [b])
- Control.Lens.SemiIso: bifoldr1 :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]
+ Control.Lens.SemiIso: bifoldr1 :: ASemiIso' a (a, a) -> SemiIso' a [a]
- Data.SemiIsoFunctor: class SemiIsoFunctor f => SemiIsoApply f where f /* g = unit /$/ f /*/ g f */ g = unit . swapped /$/ f /*/ g
+ Data.SemiIsoFunctor: class SemiIsoFunctor f => SemiIsoApply f where siunit = sipure id sipure ai = ai /$/ siunit sipureCo ai = ai `simapCo` siunit f /* g = unit /$/ f /*/ g f */ g = unit . swapped /$/ f /*/ g
- Data.SemiIsoFunctor: class SemiIsoFunctor f where simap = simapCo . fromSemi simapCo = simap . fromSemi
+ Data.SemiIsoFunctor: class SemiIsoFunctor f where simap = simapCo . rev simapCo = simap . rev
Files
- Control/Lens/SemiIso.hs +173/−74
- Data/SemiIsoFunctor.hs +76/−8
- semi-iso.cabal +3/−2
Control/Lens/SemiIso.hs view
@@ -1,5 +1,8 @@+{-# LANGUAGE TypeFamilies #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE TupleSections #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE FlexibleContexts #-} {- | Module : Control.Lens.SemiIso@@ -39,52 +42,63 @@ SemiIso', ASemiIso, ASemiIso',- ++ -- * Patterns.+ pattern SemiIso,+ -- * Constructing semi-isos. semiIso, - -- * Transforming semi-isos.- withSemiIso,- attempt,- attemptAp,- attemptUn,- attempt_,- attemptAp_,- attemptUn_,- -- * Consuming semi-isos.- fromSemi, apply, unapply,- + withSemiIso,+ viewSemiIso,+ -- * Common semi-isomorphisms and isomorphisms. unit, swapped, associated,+ morphed, constant, exact,+ bifiltered, - -- * Folds.- foldlM1,- foldrM1,- unfoldlM,- unfoldlM1,- unfoldrM,- unfoldrM1,+ -- * Semi-isos for numbers.+ _Negative, + -- * Transforming semi-isos.+ rev,+ prod,+ elimFirst,+ elimSecond,+ attempt,+ attemptAp,+ attemptUn,+ attempt_,+ attemptAp_,+ attemptUn_,+ -- * Bidirectional folds. bifoldr, bifoldr1, bifoldl,- bifoldl1+ bifoldl1,++ bifoldr_,+ bifoldr1_,+ bifoldl_,+ bifoldl1_ ) where +import Control.Arrow 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 -- | A semi-isomorphism is a partial isomorphism with weakened laws. -- @@ -95,7 +109,8 @@ -- -- Every 'Prism' is a 'SemiIso'. -- Every 'Iso' is a 'Prism'.-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 t a b = forall p f. (Exposed (Either String) p, Traversable f) + => p a (f b) -> p s (f t) -- | Non-polymorphic variant of 'SemiIso'. type SemiIso' s a = SemiIso s s a a@@ -106,11 +121,23 @@ -- | When you see this as an argument to a function, it expects a 'SemiIso''. type ASemiIso' s a = ASemiIso s s a a +-- | A nice pattern synonym for SemiIso's. Gives you the two functions, just like+-- 'viewSemiIso' or 'fromSemiIso'.+pattern SemiIso sa bt <- (viewSemiIso -> (sa, bt))+ -- | Constructs a semi isomorphism from a pair of functions that can -- fail with an error message. semiIso :: (s -> Either String a) -> (b -> Either String t) -> SemiIso s t a b semiIso sa bt = merge . dimap sa (sequenceA . fmap bt) . expose +-- | Applies the 'SemiIso'.+apply :: ASemiIso s t a b -> s -> Either String a+apply (SemiIso sa _) = sa++-- | Applies the 'SemiIso' in the opposite direction.+unapply :: ASemiIso s t a b -> b -> Either String t+unapply (SemiIso _ bt) = bt+ -- | Extracts the two functions that characterize the 'SemiIso'. withSemiIso :: ASemiIso s t a b -> ((s -> Either String a) -> (b -> Either String t) -> r) @@ -118,49 +145,9 @@ withSemiIso ai k = case ai (Retail Right (Right . Identity)) of Retail sa bt -> k sa (rmap (runIdentity . sequenceA) bt) --- | Transforms the semi-iso so that applying it in both directions never fails,--- but instead catches any errors and returns them as an @Either String a@.-attempt :: ASemiIso s t a b -> SemiIso s (Either String t) (Either String a) b-attempt = attemptAp . attemptUn---- | Transforms the semi-iso so that applying it in direction (->) never fails,--- but instead catches any errors and returns them as an @Either String a@.-attemptAp :: ASemiIso s t a b -> SemiIso s t (Either String a) b-attemptAp ai = withSemiIso ai $ \l r -> semiIso (Right . l) r---- | Transforms the semi-iso so that applying it in direction (<-) never fails,--- but instead catches any errors and returns them as an @Either String a@.-attemptUn :: ASemiIso s t a b -> SemiIso s (Either String t) a b-attemptUn ai = withSemiIso ai $ \l r -> semiIso l (Right . r)--discard :: Either a b -> Maybe b-discard = either (const Nothing) Just---- | Transforms the semi-iso like 'attempt', but ignores the error message.-attempt_ :: ASemiIso s t a b -> SemiIso s (Maybe t) (Maybe a) b-attempt_ ai = rmap (fmap discard) . attempt ai . lmap discard---- | Transforms the semi-iso like 'attemptAp', but ignores the error message.------ Very useful when you want to bifold using a prism.-attemptAp_ :: ASemiIso s t a b -> SemiIso s t (Maybe a) b-attemptAp_ ai = attemptAp ai . lmap discard---- | Transforms the semi-iso like 'attemptUn', but ignores the error message.-attemptUn_ :: ASemiIso s t a b -> SemiIso s (Maybe t) a b-attemptUn_ ai = rmap (fmap discard) . attemptUn ai---- | Applies the 'SemiIso'.-apply :: ASemiIso s t a b -> s -> Either String a-apply ai = withSemiIso ai $ \l _ -> l---- | Applies the 'SemiIso' in the opposite direction.-unapply :: ASemiIso s t a b -> b -> Either String t-unapply ai = withSemiIso ai $ \_ r -> r---- | Reverses a 'SemiIso'.-fromSemi :: ASemiIso s t a b -> SemiIso b a t s-fromSemi ai = withSemiIso ai $ \l r -> semiIso r l+-- | Extracts the two functions that characterize the 'SemiIso'.+viewSemiIso :: ASemiIso s t a b -> (s -> Either String a, b -> Either String t)+viewSemiIso ai = withSemiIso ai (,) -- | A trivial isomorphism between a and (a, ()). unit :: Iso' a (a, ())@@ -170,6 +157,14 @@ associated :: Iso' (a, (b, c)) ((a, b), c) associated = iso (\(a, (b, c)) -> ((a, b), c)) (\((a, b), c) -> (a, (b, c))) +-- | An isomorphism between two arbitrary nested tuples, as long the contained+-- types (ignoring units!) read from left to right are the same.+--+-- This is implemented using 'Data.Tuple.Morph.morph' from 'tuple-morph'.+morphed :: (HFoldable a, HUnfoldable a, HFoldable b, HUnfoldable b, Rep a ~ Rep b)+ => Iso' a b+morphed = iso morph morph+ -- | \-> Always returns the argument. -- -- \<- Maps everything to a @()@.@@ -192,6 +187,76 @@ g y | x == y = Right () | otherwise = Left "exact: not equal" +-- | Like 'filtered' but checks the predicate in both ways.+bifiltered :: (a -> Bool) -> SemiIso' a a+bifiltered p = semiIso check check+ where check x | p x = Right x+ | otherwise = Left "bifiltered: predicate failed"++-- | \-> Matches only negative numbers, turns it into a positive one.+--+-- \<- Matches only positive numbers, turns it into a negative one.+_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"++-- | Reverses a 'SemiIso'.+rev :: ASemiIso s t a b -> SemiIso b a t s+rev ai = withSemiIso ai $ \l r -> semiIso r l++-- | A product of SemiIso's.+prod :: ASemiIso s t a b -> ASemiIso s' t' a' b' + -> SemiIso (s, s') (t, t') (a, a') (b, b')+prod (SemiIso sa bt) (SemiIso sa' bt') = semiIso+ (runKleisli (Kleisli sa *** Kleisli sa')) + (runKleisli (Kleisli bt *** Kleisli bt'))++-- | In the non-polymorphic case uses an @SemiIso a ()@ to construct a+-- @SemiIso (a, b) b@, i.e. eliminates the first pair element.+elimFirst :: ASemiIso s' t' () () -> SemiIso (s', t) (t', t) t t+elimFirst ai = swapped . elimSecond ai++-- | In the non-polymorphic case uses an @SemiIso b ()@ to construct a+-- @SemiIso (a, b) a@, i.e. eliminates the second pair element.+elimSecond :: ASemiIso s' t' () () -> SemiIso (t, s') (t, t') t t+elimSecond ai = prod id ai . rev unit++-- | Transforms the semi-iso so that applying it in both directions never fails,+-- but instead catches any errors and returns them as an @Either String a@.+attempt :: ASemiIso s t a b -> SemiIso s (Either String t) (Either String a) b+attempt = attemptAp . attemptUn++-- | Transforms the semi-iso so that applying it in direction (->) never fails,+-- but instead catches any errors and returns them as an @Either String a@.+attemptAp :: ASemiIso s t a b -> SemiIso s t (Either String a) b+attemptAp (SemiIso sa bt) = semiIso (Right . sa) bt++-- | Transforms the semi-iso so that applying it in direction (<-) never fails,+-- but instead catches any errors and returns them as an @Either String a@.+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++-- | Transforms the semi-iso like 'attempt', but ignores the error message.+attempt_ :: ASemiIso s t a b -> SemiIso s (Maybe t) (Maybe a) b+attempt_ ai = rmap (fmap discard) . attempt ai . lmap discard++-- | Transforms the semi-iso like 'attemptAp', but ignores the error message.+--+-- Very useful when you want to bifold using a prism.+attemptAp_ :: ASemiIso s t a b -> SemiIso s t (Maybe a) b+attemptAp_ ai = attemptAp ai . lmap discard++-- | Transforms the semi-iso like 'attemptUn', but ignores the error message.+attemptUn_ :: ASemiIso s t a b -> SemiIso s (Maybe t) a b+attemptUn_ ai = rmap (fmap discard) . attemptUn ai+ -- | Monadic counterpart of 'foldl1' (or non-empty list counterpart of 'foldlM'). foldlM1 :: Monad m => (a -> a -> m a) -> [a] -> m a foldlM1 f (x:xs) = foldlM f x xs@@ -243,13 +308,47 @@ Just (new_a, b) -> go new_a (b : bs) Nothing -> return (a : bs) +-- | Constructs a bidirectional fold. Works with prisms.+--+-- \-> Right unfolds using the (->) part of the given semi-iso, until it fails.+--+-- \<- Right folds using the (<-) part of the given semi-iso.+bifoldr :: ASemiIso' a (b, a) -> SemiIso' a (a, [b])+bifoldr = bifoldr_ . attemptAp_++-- | Constructs a bidirectional fold. Works with prisms.+--+-- \-> Right unfolds using the (->) part of the given semi-iso, until it fails. +-- It should produce a non-empty list.+--+-- \<- Right folds a non-empty list using the (<-) part of the given semi-iso.+bifoldr1 :: ASemiIso' a (a, a) -> SemiIso' a [a]+bifoldr1 = bifoldr1_ . attemptAp_++-- | Constructs a bidirectional fold. Works with prisms.+--+-- \-> Left unfolds using the (->) part of the given semi-iso, until it fails.+--+-- \<- Left folds using the (<-) part of the given semi-iso.+bifoldl :: ASemiIso' a (a, b) -> SemiIso' a (a, [b])+bifoldl = bifoldl_ . attemptAp_++-- | Constructs a bidirectional fold. Works with prisms.+--+-- \-> Left unfolds using the (->) part of the given semi-iso, until it fails. +-- It should produce a non-empty list.+--+-- \<- Left folds a non-empty list using the (<-) part of the given semi-iso.+bifoldl1 :: ASemiIso' a (a, a) -> SemiIso' a [a]+bifoldl1 = bifoldl1_ . attemptAp_+ -- | Constructs a bidirectional fold. -- -- \-> Right unfolds using the (->) part of the given semi-iso. -- -- \<- Right folds using the (<-) part of the given semi-iso.-bifoldr :: ASemiIso a a (Maybe (b, a)) (b, a) -> SemiIso' a (a, [b])-bifoldr ai = semiIso (uf ai) (f ai)+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@@ -257,11 +356,11 @@ -- | Constructs a bidirectional fold. -- -- \-> Right unfolds using the (->) part of the given semi-iso. It should--- produce an non-empty list.+-- produce a non-empty list. -- -- \<- Right folds a non-empty list using the (<-) part of the given semi-iso.-bifoldr1 :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]-bifoldr1 ai = semiIso (uf ai) (f ai)+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@@ -271,8 +370,8 @@ -- \-> Left unfolds using the (->) part of the given semi-iso. -- -- \<- Left folds using the (<-) part of the given semi-iso.-bifoldl :: ASemiIso a a (Maybe (a, b)) (a, b) -> SemiIso' a (a, [b])-bifoldl ai = semiIso (uf ai) (f ai)+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@@ -280,11 +379,11 @@ -- | Constructs a bidirectional fold. -- -- \-> Left unfolds using the (->) part of the given semi-iso. It should--- produce an non-empty list.+-- produce a non-empty list. -- -- \<- Left folds a non-empty list using the (<-) part of the given semi-iso.-bifoldl1 :: ASemiIso a a (Maybe (a, a)) (a, a) -> SemiIso' a [a]-bifoldl1 ai = semiIso (uf ai) (f ai)+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
Data/SemiIsoFunctor.hs view
@@ -1,3 +1,5 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE PatternSynonyms #-} {- | Module : Data.SemiIsoFunctor Description : Functors from the category of semi-isomoprihsms to Hask.@@ -13,18 +15,19 @@ instantiated by both covariant (like Parser) and contravariant (like Printer) functors. Therefore it can be used as a common interface to unify parsing and pretty printing.--Operator names are up to bikeshedding :) -} module Data.SemiIsoFunctor where import Control.Lens.Cons import Control.Lens.Empty import Control.Lens.SemiIso+import Data.Tuple.Morph infixl 3 /|/-infixl 4 /$/+infixl 4 /$/, ~$/, /$~, ~$~ infixl 5 /*/, /*, */+infixl 1 //=+infixr 1 =// -- | A functor from the category of semi-isomorphisms to Hask. --@@ -42,18 +45,50 @@ class SemiIsoFunctor f where -- | The contravariant map. simap :: ASemiIso' a b -> f b -> f a- simap = simapCo . fromSemi- + simap = simapCo . rev+ -- | The covariant map. simapCo :: ASemiIso' a b -> f a -> f b- simapCo = simap . fromSemi- + simapCo = simap . rev+ {-# MINIMAL simap | simapCo #-} -- | A infix operator for 'simap'. (/$/) :: SemiIsoFunctor f => ASemiIso' a b -> f b -> f a (/$/) = simap +-- | > ai /$~ f = ai . morphed /$/ f+--+-- This operator handles all the hairy stuff with uncurried application:+-- it reassociates the argument tuple and removes unnecessary (or adds necessary)+-- units to match the function type. You don't have to use @/*@ and @*/@ with this+-- operator.+(/$~) :: (SemiIsoFunctor f, HFoldable b', HFoldable b,+ HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b)+ => ASemiIso' a b' -> f b -> f a+-- TODO GHC 7.10: haddock doesn't work with pattern synynonyms yet+-- (SemiIso f g) /$~ h = semiIso f g . morphed /$/ h+ai /$~ h = withSemiIso ai $ \f g -> semiIso f g . morphed /$/ h++-- | > ai ~$/ f = morphed . ai /$/ f+(~$/) :: (SemiIsoFunctor f, HFoldable a', HFoldable a,+ HUnfoldable a', HUnfoldable a, Rep a' ~ Rep a)+ => ASemiIso' a' b -> f b -> f a+-- TODO GHC 7.10: haddock doesn't work with pattern synynonyms yet+--(SemiIso f g) ~$/ h = morphed . semiIso f g /$/ h+ai ~$/ h = withSemiIso ai $ \f g -> morphed . semiIso f g /$/ h++-- | > ai ~$~ f = morphed . ai . morphed /$/ f+(~$~) :: (SemiIsoFunctor f,+ HFoldable a, HUnfoldable a,+ HFoldable b, HUnfoldable b,+ HFoldable b', HUnfoldable b',+ Rep b' ~ Rep b, Rep b' ~ Rep a)+ => ASemiIso b' b' b' b' -> f b -> f a+-- TODO GHC 7.10: haddock doesn't work with pattern synynonyms yet+--(SemiIso f g) ~$~ h = morphed . semiIso f g . morphed /$/ h+ai ~$~ h = withSemiIso ai $ \f g -> morphed . semiIso f g . morphed /$/ h+ -- | Equivalent of 'Applicative' for 'SemiIsoFunctor'. -- -- However, this class implements uncurried application, unlike @@ -63,7 +98,15 @@ -- -- > TODO (they should be fine) class SemiIsoFunctor f => SemiIsoApply f where+ siunit :: f ()+ siunit = sipure id+ sipure :: ASemiIso' a () -> f a+ sipure ai = ai /$/ siunit++ sipureCo :: ASemiIso' () a -> f a+ sipureCo ai = ai `simapCo` siunit+ (/*/) :: f a -> f b -> f (a, b) (/*) :: f a -> f () -> f a@@ -72,7 +115,7 @@ (*/) :: f () -> f b -> f b f */ g = unit . swapped /$/ f /*/ g - {-# MINIMAL sipure, (/*/) #-}+ {-# MINIMAL (siunit | sipure), (/*/) #-} -- | Equivalent of 'Alternative' for 'SemiIsoFunctor'. --@@ -89,6 +132,31 @@ simany v = sisome v /|/ sipure _Empty {-# MINIMAL siempty, (/|/) #-}++-- | An analogue of 'Monad' for 'SemiIsoFunctor'.+--+-- Because of the 'no throwing away' rule bind has to \"return\"+-- both @a@ and @b@.+class SemiIsoApply m => SemiIsoMonad m where+ (//=) :: m a -> (a -> m b) -> m (a, b)+ m //= f = swapped /$/ (f =// m)++ (=//) :: (b -> m a) -> m b -> m (a, b)+ f =// m = swapped /$/ (m //= f)++ {-# MINIMAL (//=) | (=//) #-}++-- | A SemiIsoMonad with fixed point operator.+class SemiIsoMonad m => SemiIsoFix m where+ sifix :: (a -> m a) -> m a+ sifix f = dup /$/ (f =//= f)+ where dup = semiIso (\a -> Right (a, a)) (Right . fst)++ -- | Fixed point combined with bind, it's so symmetric!+ (=//=) :: (a -> m b) -> (b -> m a) -> m (a, b)+ f =//= g = sifix (\(a, b) -> g b /*/ f a)++ {-# MINIMAL sifix | (=//=) #-} -- | Equivalent of 'sequence'. --
semi-iso.cabal view
@@ -1,5 +1,5 @@ name: semi-iso-version: 0.3.0.0+version: 0.4.0.0 synopsis: Weakened partial isomorphisms that work with lenses. description: Semi-isomorphisms are partial isomorphisms with weakened iso laws. And they work with Iso and Prism from @lens@!@@ -24,5 +24,6 @@ Control.Lens.Internal.SemiIso Data.SemiIsoFunctor Data.Profunctor.Exposed- build-depends: base >= 4 && < 5, profunctors, transformers, lens+ build-depends: base >= 4 && < 5, profunctors, transformers, lens, tuple-morph default-language: Haskell2010+ ghc-options: -Wall