semi-iso 0.5.0.0 → 1.0.0.0
raw patch · 7 files changed
+445/−258 lines, 7 filesdep +semigroupoidsPVP ok
version bump matches the API change (PVP)
Dependencies added: semigroupoids
API changes (from Hackage documentation)
- Control.Lens.SemiIso: instance Arrow ReifiedSemiIso'
- Data.SemiIsoFunctor: (*/) :: SemiIsoApply f => f () -> f b -> f b
- Data.SemiIsoFunctor: (/$/) :: SemiIsoFunctor f => ASemiIso' a b -> f b -> f a
- 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: (/*) :: SemiIsoApply f => f a -> f () -> f a
- Data.SemiIsoFunctor: (/*/) :: SemiIsoApply f => f a -> f b -> f (a, b)
- Data.SemiIsoFunctor: (//=) :: SemiIsoMonad m => m a -> (a -> m b) -> m (a, b)
- Data.SemiIsoFunctor: (/?/) :: SemiIsoAlternative f => f a -> String -> f a
- Data.SemiIsoFunctor: (/|/) :: SemiIsoAlternative f => f a -> f a -> f a
- 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 SemiIsoApply f => SemiIsoAlternative f where sisome v = _Cons /$/ v /*/ simany v simany v = sisome v /|/ sipure _Empty
- 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 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 SemiIsoFunctor f where simap = simapCo . rev simapCo = simap . rev
- Data.SemiIsoFunctor: class SemiIsoApply m => SemiIsoMonad m where m //= f = swapped /$/ (f =// m) f =// m = swapped /$/ (m //= f)
- Data.SemiIsoFunctor: siempty :: SemiIsoAlternative f => f a
- Data.SemiIsoFunctor: sifail :: SemiIsoApply f => String -> f a
- Data.SemiIsoFunctor: sifix :: SemiIsoFix m => (a -> m a) -> m a
- Data.SemiIsoFunctor: simany :: SemiIsoAlternative f => f a -> f [a]
- Data.SemiIsoFunctor: simap :: SemiIsoFunctor f => ASemiIso' a b -> f b -> f a
- Data.SemiIsoFunctor: simapCo :: SemiIsoFunctor f => ASemiIso' a b -> f a -> f b
- Data.SemiIsoFunctor: sipure :: SemiIsoApply f => ASemiIso' a () -> f a
- Data.SemiIsoFunctor: sipureCo :: SemiIsoApply f => ASemiIso' () a -> f a
- Data.SemiIsoFunctor: sireplicate :: SemiIsoApply f => Int -> f a -> f [a]
- Data.SemiIsoFunctor: sireplicate_ :: SemiIsoApply f => Int -> f () -> f ()
- Data.SemiIsoFunctor: sisequence :: SemiIsoApply f => [f a] -> f [a]
- Data.SemiIsoFunctor: sisequence_ :: SemiIsoApply f => [f ()] -> f ()
- Data.SemiIsoFunctor: sisome :: SemiIsoAlternative f => f a -> f [a]
- Data.SemiIsoFunctor: siunit :: SemiIsoApply f => f ()
- Data.SemiIsoFunctor.Wrapped: WrappedCovariant :: m a -> WrappedCovariant m a
- Data.SemiIsoFunctor.Wrapped: instance (Monad m, Alternative m) => SemiIsoAlternative (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Alternative m => Alternative (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Applicative m => Applicative (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Functor m => Functor (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Monad m => Monad (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Monad m => SemiIsoApply (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Monad m => SemiIsoFunctor (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: instance Monad m => SemiIsoMonad (WrappedCovariant m)
- Data.SemiIsoFunctor.Wrapped: newtype WrappedCovariant m a
- Data.SemiIsoFunctor.Wrapped: runCovariant :: WrappedCovariant m a -> m a
+ Control.Category.Reader: ReaderCT :: (env -> cat a b) -> ReaderCT env cat a b
+ Control.Category.Reader: instance CatPlus cat => CatPlus (ReaderCT env cat)
+ Control.Category.Reader: instance CatTrans (ReaderCT env)
+ Control.Category.Reader: instance Category cat => Category (ReaderCT env cat)
+ Control.Category.Reader: instance Coproducts cat => Coproducts (ReaderCT env cat)
+ Control.Category.Reader: instance Products cat => Products (ReaderCT env cat)
+ Control.Category.Reader: instance SIArrow cat => SIArrow (ReaderCT env cat)
+ Control.Category.Reader: newtype ReaderCT env cat a b
+ Control.Category.Reader: runReaderCT :: ReaderCT env cat a b -> env -> cat a b
+ Control.Category.Structures: (***) :: Products cat => cat a b -> cat c d -> cat (a, c) (b, d)
+ Control.Category.Structures: (+++) :: Coproducts cat => cat a b -> cat c d -> cat (Either a c) (Either b d)
+ Control.Category.Structures: (/+/) :: CatPlus cat => cat a b -> cat a b -> cat a b
+ Control.Category.Structures: cempty :: CatPlus cat => cat a b
+ Control.Category.Structures: class Category cat => CatPlus cat
+ Control.Category.Structures: class CatTrans t
+ Control.Category.Structures: class Category cat => Coproducts cat where left a = a +++ id right a = id +++ a a +++ b = left a >>> right b
+ Control.Category.Structures: class Category cat => Products cat where first a = a *** id second a = id *** a a *** b = first a >>> second b
+ Control.Category.Structures: clift :: (CatTrans t, Category cat) => cat a b -> t cat a b
+ Control.Category.Structures: first :: Products cat => cat a b -> cat (a, c) (b, c)
+ Control.Category.Structures: instance CatPlus cat => CatPlus (Dual cat)
+ Control.Category.Structures: instance Coproducts (->)
+ Control.Category.Structures: instance Coproducts cat => Coproducts (Dual cat)
+ Control.Category.Structures: instance Monad m => Coproducts (Kleisli m)
+ Control.Category.Structures: instance Monad m => Products (Kleisli m)
+ Control.Category.Structures: instance MonadPlus m => CatPlus (Kleisli m)
+ Control.Category.Structures: instance Products (->)
+ Control.Category.Structures: instance Products cat => Products (Dual cat)
+ Control.Category.Structures: left :: Coproducts cat => cat a b -> cat (Either a c) (Either b c)
+ Control.Category.Structures: right :: Coproducts cat => cat a b -> cat (Either c a) (Either c b)
+ Control.Category.Structures: second :: Products cat => cat a b -> cat (c, a) (c, b)
+ Control.Lens.SemiIso: instance CatPlus ReifiedSemiIso'
+ Control.Lens.SemiIso: instance Coproducts ReifiedSemiIso'
+ Control.Lens.SemiIso: instance Products ReifiedSemiIso'
+ Control.SIArrow: (#<<) :: SIArrow cat => ASemiIso' c b -> cat a b -> cat a c
+ Control.SIArrow: (#>>) :: SIArrow cat => ASemiIso' b a -> cat b c -> cat a c
+ Control.SIArrow: (*/) :: SIArrow cat => cat () () -> cat () a -> cat () a
+ Control.SIArrow: (/$/) :: SIArrow cat => ASemiIso' b' b -> cat a b -> cat a b'
+ Control.SIArrow: (/$~) :: (SIArrow cat, HFoldable b', HFoldable b, HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b) => ASemiIso' a b' -> cat c b -> cat c a
+ Control.SIArrow: (/*) :: SIArrow cat => cat () a -> cat () () -> cat () a
+ Control.SIArrow: (/*/) :: SIArrow cat => cat () b -> cat () c -> cat () (b, c)
+ Control.SIArrow: (/?/) :: SIArrow cat => cat a b -> String -> cat a b
+ Control.SIArrow: (<<#) :: SIArrow cat => cat b c -> ASemiIso' b a -> cat a c
+ Control.SIArrow: (<<^) :: SIArrow cat => cat b c -> ASemiIso' a b -> cat a c
+ Control.SIArrow: (>>#) :: SIArrow cat => cat a b -> ASemiIso' c b -> cat a c
+ Control.SIArrow: (>>^) :: SIArrow cat => cat a b -> ASemiIso' b c -> cat a c
+ Control.SIArrow: (^<<) :: SIArrow cat => ASemiIso' b c -> cat a b -> cat a c
+ Control.SIArrow: (^>>) :: SIArrow cat => ASemiIso' a b -> cat b c -> cat a c
+ Control.SIArrow: class (Products cat, Coproducts cat, CatPlus cat) => SIArrow cat where siarr = sipure . rev sipure = siarr . rev sisome v = _Cons /$/ v /*/ simany v simany v = sisome v /+/ sipure _Empty
+ Control.SIArrow: instance MonadPlus m => SIArrow (Kleisli m)
+ Control.SIArrow: instance SIArrow ReifiedSemiIso'
+ Control.SIArrow: instance SIArrow cat => SIArrow (Dual cat)
+ Control.SIArrow: siarr :: SIArrow cat => ASemiIso' a b -> cat a b
+ Control.SIArrow: sibind :: SIArrow cat => ASemiIso a (cat a b) (cat a b) b -> cat a b
+ Control.SIArrow: sifail :: SIArrow cat => String -> cat a b
+ Control.SIArrow: simany :: SIArrow cat => cat () b -> cat () [b]
+ Control.SIArrow: sipure :: SIArrow cat => ASemiIso' b a -> cat a b
+ Control.SIArrow: sireplicate :: SIArrow cat => Int -> cat () a -> cat () [a]
+ Control.SIArrow: sireplicate_ :: SIArrow cat => Int -> cat () () -> cat () ()
+ Control.SIArrow: sisequence :: SIArrow cat => [cat () a] -> cat () [a]
+ Control.SIArrow: sisequence_ :: SIArrow cat => [cat () ()] -> cat () ()
+ Control.SIArrow: sisome :: SIArrow cat => cat () b -> cat () [b]
Files
- Control/Category/Reader.hs +47/−0
- Control/Category/Structures.hs +113/−0
- Control/Lens/SemiIso.hs +28/−7
- Control/SIArrow.hs +206/−0
- Data/SemiIsoFunctor.hs +0/−204
- Data/SemiIsoFunctor/Wrapped.hs +0/−37
- semi-iso.cabal +51/−10
+ Control/Category/Reader.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE TypeFamilies #-}+{- |+Module : Control.Category.Reader+Description : Reader category transformer.+Copyright : (c) Paweł Nowak+License : MIT++Maintainer : Paweł Nowak <pawel834@gmail.com>+Stability : experimental++Provides a Reader category transformer.+-}+module Control.Category.Reader (+ ReaderCT(..)+ ) where++import Control.Category+import Control.Category.Structures+import Control.Lens.Iso+import Control.Lens.SemiIso+import Control.SIArrow+import Prelude hiding (id, (.))++newtype ReaderCT env cat a b = ReaderCT { runReaderCT :: env -> cat a b }++instance CatTrans (ReaderCT env) where+ clift = ReaderCT . const++instance Category cat => Category (ReaderCT env cat) where+ id = clift id+ ReaderCT f . ReaderCT g = ReaderCT $ \x -> f x . g x++instance Products cat => Products (ReaderCT env cat) where+ ReaderCT f *** ReaderCT g = ReaderCT $ \x -> f x *** g x++instance Coproducts cat => Coproducts (ReaderCT env cat) where+ ReaderCT f +++ ReaderCT g = ReaderCT $ \x -> f x +++ g x++instance CatPlus cat => CatPlus (ReaderCT env cat) where+ cempty = clift cempty+ ReaderCT f /+/ ReaderCT g = ReaderCT $ \x -> f x /+/ g x++instance SIArrow cat => SIArrow (ReaderCT env cat) where+ siarr = clift . siarr+ sibind ai = ReaderCT $ \env -> sibind+ (iso id (flip runReaderCT env) . cloneSemiIso ai . iso (flip runReaderCT env) id)
+ Control/Category/Structures.hs view
@@ -0,0 +1,113 @@+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE ConstraintKinds #-}+{- |+Module : Control.Category.Structures+Description : Structures in a category.+Copyright : (c) Paweł Nowak+License : MIT++Maintainer : Paweł Nowak <pawel834@gmail.com>+Stability : experimental++This module defines some basic structures in a category in a more fine-grained+way then "Control.Arrow".++Unfortunately names in this module clash with "Control.Arrow".+-}+module Control.Category.Structures where++import Control.Arrow (Kleisli(..))+import qualified Control.Arrow as BadArrow+import Control.Category+import Control.Monad+import Data.Semigroupoid.Dual+import Prelude hiding (id, (.))++infixl 3 ***+infixl 2 ++++infixl 3 /+/++-- | A category with finite products.+class Category cat => Products cat where+ -- | Send the first component of the input through the argument arrow, and copy the rest unchanged to the output.+ --+ -- @first a@ is equal to @a *** id@.+ first :: cat a b -> cat (a, c) (b, c)+ first a = a *** id++ -- | A mirror image of 'first'.+ --+ -- @second a@ is equal to @id *** a@.+ second :: cat a b -> cat (c, a) (c, b)+ second a = id *** a++ -- | A product of two arrows.+ -- Split the input between the two argument arrows and combine their output.+ (***) :: cat a b -> cat c d -> cat (a, c) (b, d)+ a *** b = first a >>> second b++ {-# MINIMAL (***) | first, second #-}++instance Monad m => Products (Kleisli m) where+ (***) = (BadArrow.***)++instance Products cat => Products (Dual cat) where+ Dual f *** Dual g = Dual $ second g >>> first f++instance Products (->) where+ (***) = (BadArrow.***)++-- | A category with finite coproducts.+class Category cat => Coproducts cat where+ -- | Feed marked inputs through the argument arrow, passing the rest through unchanged to the output.+ --+ -- @left a@ is equal to @a +++ id@.+ left :: cat a b -> cat (Either a c) (Either b c)+ left a = a +++ id++ -- | A mirror image of left.+ --+ -- @right a@ is equal to @id +++ a@.+ right :: cat a b -> cat (Either c a) (Either c b)+ right a = id +++ a++ -- | A coproduct of two arrows.+ -- Split the input between the two argument arrows, retagging and merging their outputs.+ (+++) :: cat a b -> cat c d -> cat (Either a c) (Either b d)+ a +++ b = left a >>> right b++ {-# MINIMAL (+++) | left, right #-}++instance Monad m => Coproducts (Kleisli m) where+ (+++) = (BadArrow.+++)++instance Coproducts cat => Coproducts (Dual cat) where+ Dual f +++ Dual g = Dual $ right g >>> left f++instance Coproducts (->) where+ (+++) = (BadArrow.+++)++-- | A category @cat@ is a CatPlus when @cat a b@ is a monoid for all a, b.+class Category cat => CatPlus cat where+ -- | The identity of '/+/'.+ cempty :: cat a b+ -- | An associative operation on arrows.+ (/+/) :: cat a b -> cat a b -> cat a b++ {-# MINIMAL cempty, (/+/) #-}++instance MonadPlus m => CatPlus (Kleisli m) where+ cempty = BadArrow.zeroArrow+ (/+/) = (BadArrow.<+>)++instance CatPlus cat => CatPlus (Dual cat) where+ cempty = Dual cempty+ Dual f /+/ Dual g = Dual $ f /+/ g++-- | A category transformer.+class CatTrans t where+ -- | Lift an arrow from the base category.+ clift :: Category cat => cat a b -> t cat a b++ {-# MINIMAL clift #-}
Control/Lens/SemiIso.hs view
@@ -97,9 +97,9 @@ bifoldl1_ ) where -import Prelude hiding (id, (.))-import Control.Arrow+import Control.Arrow (Kleisli(..)) import Control.Category+import Control.Category.Structures import Control.Lens.Internal.SemiIso import Control.Lens.Iso import Data.Foldable@@ -107,6 +107,7 @@ import Data.Profunctor.Exposed import Data.Traversable import Data.Tuple.Morph+import Prelude hiding (id, (.)) -- | A semi-isomorphism is a partial isomorphism with weakened laws. -- @@ -140,11 +141,7 @@ id = ReifiedSemiIso' id ReifiedSemiIso' f . ReifiedSemiIso' g = ReifiedSemiIso' (g . f) --- | This in an __/incomplete/__ instance, 'arr' and '(&&&)' are undefined.-instance Arrow ReifiedSemiIso' where- arr = undefined- (&&&) = undefined-+instance Products ReifiedSemiIso' where -- TODO: pattern synonyms dont work here for some reason first (ReifiedSemiIso' ai) = withSemiIso ai $ \f g -> ReifiedSemiIso' $ cloneSemiIso $@@ -160,6 +157,30 @@ withSemiIso ai $ \f g -> withSemiIso ai' $ \f' g' -> semiIso (runKleisli $ Kleisli f *** Kleisli f') (runKleisli $ Kleisli g *** Kleisli g')++instance Coproducts ReifiedSemiIso' where+ left (ReifiedSemiIso' ai) = withSemiIso ai $ \f g ->+ ReifiedSemiIso' $ cloneSemiIso $+ semiIso (runKleisli $ left $ Kleisli f)+ (runKleisli $ left $ Kleisli g)++ right (ReifiedSemiIso' ai) = withSemiIso ai $ \f g ->+ ReifiedSemiIso' $ cloneSemiIso $+ semiIso (runKleisli $ right $ Kleisli f)+ (runKleisli $ right $ 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')++instance CatPlus ReifiedSemiIso' where+ cempty = ReifiedSemiIso' $ alwaysFailing "cempty"++ ReifiedSemiIso' ai /+/ ReifiedSemiIso' ai' = ReifiedSemiIso' $+ withSemiIso ai $ \f g -> withSemiIso ai' $ \f' g' ->+ semiIso (runKleisli $ Kleisli f /+/ Kleisli f')+ (runKleisli $ Kleisli g /+/ Kleisli g') -- | Constructs a semi isomorphism from a pair of functions that can -- fail with an error message.
+ Control/SIArrow.hs view
@@ -0,0 +1,206 @@+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE TypeFamilies #-}+{-# LANGUAGE ConstraintKinds #-}+{-# LANGUAGE FlexibleContexts #-}+{-# LANGUAGE ScopedTypeVariables #-}+{- |+Module : Control.SIArrow+Description : Categories of reversible computations.+Copyright : (c) Paweł Nowak+License : MIT++Maintainer : Paweł Nowak <pawel834@gmail.com>+Stability : experimental++Categories of reversible computations.+-}+module Control.SIArrow (+ -- * Arrow.+ SIArrow(..),+ (^>>), (>>^), (^<<), (<<^),+ (#>>), (>>#), (#<<), (<<#),++ -- * Functor and applicative.+ (/$/), (/$~),+ (/*/), (/*), (*/),++ -- * Signaling errors.+ sifail, (/?/),++ -- * Combinators.+ sisequence,+ sisequence_,+ sireplicate,+ sireplicate_+ ) where++import Control.Arrow (Kleisli(..))+import Control.Category+import Control.Category.Structures+import Control.Lens.Cons+import Control.Lens.Empty+import Control.Lens.Iso+import Control.Lens.SemiIso+import Control.Monad+import Data.Semigroupoid.Dual+import Data.Tuple.Morph+import Prelude hiding (id, (.))++infixr 1 ^>>, ^<<, #>>, #<<+infixr 1 >>^, <<^, >>#, <<#+infixl 4 /$/, /$~+infixl 5 /*/, */, /*+infixl 3 /?/++-- | A category equipped with an embedding 'siarr' from @SemiIso@ into @cat@ and some+-- additional structure.+--+-- SIArrow abstracts categories of reversible computations+-- (with reversible side effects).+--+-- The category @cat@ should contain @SemiIso@ as a sort of+-- \"subcategory of pure computations\".+class (Products cat, Coproducts cat, CatPlus cat) => SIArrow cat where+ -- | Allows you to lift a SemiIso into @cat@. The resulting arrow should be+ -- in some sense minimal or \"pure\", similiar to 'pure', 'return' and+ -- 'arr' from "Control.Category".+ siarr :: ASemiIso' a b -> cat a b+ siarr = sipure . rev++ -- | Reversed version of 'siarr'.+ --+ -- Use this where you would use 'pure'.+ sipure :: ASemiIso' b a -> cat a b+ sipure = siarr . rev++ -- | Allows a computation to depend on a its input value.+ --+ -- I am not sure if this is the right way to get that ArrowApply or Monad+ -- like power. It seems quite easy to break the parser/pretty-printer inverse+ -- guarantee using this. On the other hand we have to be careful only when+ -- constructing the SemiIso using 'iso'/'semiIso' - and with an invalid SemiIso+ -- we could break everything anyway using 'siarr'.+ sibind :: ASemiIso a (cat a b) (cat a b) b -> cat a b++ -- | @sisome v@ repeats @v@ as long as possible, but no less then once.+ sisome :: cat () b -> cat () [b]+ sisome v = _Cons /$/ v /*/ simany v++ -- | @simany v@ repeats @v@ as long as possible.+ simany :: cat () b -> cat () [b]+ simany v = sisome v /+/ sipure _Empty++ {-# MINIMAL (siarr | sipure), sibind #-}++instance MonadPlus m => SIArrow (Kleisli m) where+ siarr ai = Kleisli $ either fail return . apply ai+ sibind ai = Kleisli $ \a -> either fail (($ a) . runKleisli) $ apply ai a++instance SIArrow cat => SIArrow (Dual cat) where+ siarr = Dual . sipure+ sibind ai = Dual $ sibind (iso id getDual . rev ai . iso getDual id)++instance SIArrow ReifiedSemiIso' where+ siarr = reifySemiIso+ sibind ai = ReifiedSemiIso' $+ semiIso (\a -> apply ai a >>= flip apply a . runSemiIso)+ (\b -> unapply ai b >>= flip unapply b . runSemiIso)++-- | Composes a SemiIso with an arrow.+(^>>) :: SIArrow cat => ASemiIso' a b -> cat b c -> cat a c+f ^>> a = a . siarr f++-- | Composes an arrow with a SemiIso.+(>>^) :: SIArrow cat => cat a b -> ASemiIso' b c -> cat a c+a >>^ f = siarr f . a++-- | Composes a SemiIso with an arrow, backwards.+(^<<) :: SIArrow cat => ASemiIso' b c -> cat a b -> cat a c+f ^<< a = siarr f . a++-- | Composes an arrow with a SemiIso, backwards.+(<<^) :: SIArrow cat => cat b c -> ASemiIso' a b -> cat a c+a <<^ f = a . siarr f++-- | Composes a reversed SemiIso with an arrow.+(#>>) :: SIArrow cat => ASemiIso' b a -> cat b c -> cat a c+f #>> a = a . sipure f++-- | Composes an arrow with a reversed SemiIso.+(>>#) :: SIArrow cat => cat a b -> ASemiIso' c b -> cat a c+a >># f = sipure f . a++-- | Composes a reversed SemiIso with an arrow, backwards.+(#<<) :: SIArrow cat => ASemiIso' c b -> cat a b -> cat a c+f #<< a = sipure f . a++-- | Composes an arrow with a reversed SemiIso, backwards.+(<<#) :: SIArrow cat => cat b c -> ASemiIso' b a -> cat a c+a <<# f = a . sipure f++-- | Postcomposes an arrow with a reversed SemiIso.+-- The analogue of '<$>' and synonym for '#<<'.+(/$/) :: SIArrow cat => ASemiIso' b' b -> cat a b -> cat a b'+(/$/) = (#<<)++-- | Convenient fmap.+--+-- > 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.+(/$~) :: (SIArrow cat, HFoldable b', HFoldable b,+ HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b)+ => ASemiIso' a b' -> cat c b -> cat c a+ai /$~ h = cloneSemiIso ai . morphed /$/ h++-- | The product of two arrows with duplicate units removed. Side effect are+-- sequenced from left to right.+--+-- The uncurried analogue of '<*>'.+(/*/) :: SIArrow cat => cat () b -> cat () c -> cat () (b, c)+a /*/ b = unit ^>> (a *** b)++-- | The product of two arrows, where the second one has no input and no output+-- (but can have side effects), with duplicate units removed. Side effect are+-- sequenced from left to right.+--+-- The uncurried analogue of '<*'.+(/*) :: SIArrow cat => cat () a -> cat () () -> cat () a+f /* g = unit /$/ f /*/ g++-- | The product of two arrows, where the first one has no input and no output+-- (but can have side effects), with duplicate units removed. Side effect are+-- sequenced from left to right.+--+-- The uncurried analogue of '*>'.+(*/) :: SIArrow cat => cat () () -> cat () a -> cat () a+f */ g = unit . swapped /$/ f /*/ g++-- | An arrow that fails with an error message.+sifail :: SIArrow cat => String -> cat a b+sifail = siarr . alwaysFailing++-- | Provides an error message in the case of failure.+(/?/) :: SIArrow cat => cat a b -> String -> cat a b+f /?/ msg = f /+/ sifail msg++-- | Equivalent of 'sequence'.+sisequence :: SIArrow cat => [cat () a] -> cat () [a]+sisequence [] = sipure _Empty+sisequence (x:xs) = _Cons /$/ x /*/ sisequence xs++-- | Equivalent of 'sequence_', restricted to units.+sisequence_ :: SIArrow cat => [cat () ()] -> cat () ()+sisequence_ [] = sipure _Empty+sisequence_ (x:xs) = unit /$/ x /*/ sisequence_ xs++-- | Equivalent of 'replicateM'.+sireplicate :: SIArrow cat => Int -> cat () a -> cat () [a]+sireplicate n f = sisequence (replicate n f)++-- | Equivalent of 'replicateM_', restricted to units.+sireplicate_ :: SIArrow cat => Int -> cat () () -> cat () ()+sireplicate_ n f = sisequence_ (replicate n f)
− Data/SemiIsoFunctor.hs
@@ -1,204 +0,0 @@-{-# LANGUAGE TypeFamilies #-}-{-# LANGUAGE PatternSynonyms #-}-{- |-Module : Data.SemiIsoFunctor-Description : Functors from the category of semi-isomoprihsms to Hask.-Copyright : (c) Paweł Nowak-License : MIT--Maintainer : Paweł Nowak <pawel834@gmail.com>-Stability : experimental--Defines a functor from the category of semi-isomoprihsms to Hask.--It can be 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.--}-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 5 /*/, /*, */-infixl 1 //=-infixr 1 =//---- | A functor from the category of semi-isomorphisms to Hask. We can think of it as--- if it was both covariant and contravariant in its single argument.------ The contravariant map is used by default to provide compatibility with --- Prisms (otherwise you would have to reverse them in most cases).------ This is really a pair of functors @F : SemiIso -> Hask@,--- @G : SemiIso^op -> Hask@ satisfying:------ > F(X) = G(X)--- > F(f) = G(f^-1)------ Instances should satisfy laws:--- --- [/functoriality/]------ prop> simap id = id--- prop> simap (f . g) = simap g . simap f------ [/inverse/]------ prop> simap f = simapCo (rev f)-class SemiIsoFunctor f where- -- | The contravariant map.- simap :: ASemiIso' a b -> f b -> f a- simap = simapCo . rev-- -- | The covariant map.- simapCo :: ASemiIso' a b -> f a -> f b- 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-ai /$~ h = cloneSemiIso ai . 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-ai ~$/ h = morphed . cloneSemiIso ai /$/ 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-ai ~$~ h = morphed . cloneSemiIso ai . morphed /$/ h---- | An applicative semi-iso functor, i. e. a lax monoidal functor from @SemiIso@--- to @Hask@.------ Instances should satisfy laws:--- --- [/homomorphism/]------ prop> sipure f /*/ sipure g = sipure (f `prod` g)------ [/associativity/]------ prop> f /*/ (g /*/ h) = associated /$/ (f /*/ g) /*/ h------ [/unitality/]------ prop> siunit /*/ x = swapped . rev unit /$/ x--- prop> x /*/ siunit = rev unit /$/ x------ Additionally it should be consistent with the default implementation:------ prop> sipure ai = ai /$/ siunit--- prop> sipureCo ai = ai `simapCo` siunit------ prop> f /* g = unit /$/ f /*/ g--- prop> f */ g = unit . swapped /$/ f /*/ g-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- f /* g = unit /$/ f /*/ g-- (*/) :: f () -> f b -> f b- f */ g = unit . swapped /$/ f /*/ g-- {-# MINIMAL (siunit | sipure), (/*/) #-}---- | Fails with a message.-sifail :: SemiIsoApply f => String -> f a-sifail msg = alwaysFailing msg /$/ siunit---- | Equivalent of 'Alternative' for 'SemiIsoFunctor'.------ @f a@ should form a monoid with identity 'siempty' and binary--- operation '/|/'.-class SemiIsoApply f => SemiIsoAlternative f where- siempty :: f a- (/|/) :: f a -> f a -> f a-- sisome :: f a -> f [a]- sisome v = _Cons /$/ v /*/ simany v-- simany :: f a -> f [a]- simany v = sisome v /|/ sipure _Empty-- {-# MINIMAL siempty, (/|/) #-}---- | Provides an error message in the case of failure.-(/?/) :: SemiIsoAlternative f => f a -> String -> f a-f /?/ msg = f /|/ sifail msg---- | 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'.-sisequence :: SemiIsoApply f => [f a] -> f [a]-sisequence [] = sipure _Empty-sisequence (x:xs) = _Cons /$/ x /*/ sisequence xs---- | Equivalent of 'sequence_', restricted to units.-sisequence_ :: SemiIsoApply f => [f ()] -> f ()-sisequence_ [] = sipure _Empty-sisequence_ (x:xs) = unit /$/ x /*/ sisequence_ xs---- | Equivalent of 'replicateM'.-sireplicate :: SemiIsoApply f => Int -> f a -> f [a]-sireplicate n f = sisequence (replicate n f)---- | Equivalent of 'replicateM_', restricted to units.-sireplicate_ :: SemiIsoApply f => Int -> f () -> f ()-sireplicate_ n f = sisequence_ (replicate n f)
− Data/SemiIsoFunctor/Wrapped.hs
@@ -1,37 +0,0 @@-{-# LANGUAGE FlexibleInstances #-}-{-# LANGUAGE GeneralizedNewtypeDeriving #-}-{- |-Module : Data.SemiIsoFunctor.Wrapped-Description : SemiIso instances for wrapped monads.-Copyright : (c) Paweł Nowak-License : MIT--Maintainer : Paweł Nowak <pawel834@gmail.com>-Stability : experimental--Every monad (with fail) is a SemiIsoMonad.--}-module Data.SemiIsoFunctor.Wrapped where--import Control.Applicative-import Control.Lens.SemiIso-import Control.Monad-import Data.SemiIsoFunctor---- | A wrapped covariant functor.-newtype WrappedCovariant m a = WrappedCovariant { runCovariant :: m a }- deriving (Functor, Applicative, Alternative, Monad)--instance Monad m => SemiIsoFunctor (WrappedCovariant m) where- simapCo ai m = m >>= either fail return . apply ai--instance Monad m => SemiIsoApply (WrappedCovariant m) where- sipure ai = either fail return (unapply ai ())- f /*/ g = liftM2 (,) f g--instance (Monad m, Alternative m) => SemiIsoAlternative (WrappedCovariant m) where- siempty = empty- f /|/ g = f <|> g--instance Monad m => SemiIsoMonad (WrappedCovariant m) where- f //= g = f >>= (\x -> g x >>= \y -> return (x, y))
semi-iso.cabal view
@@ -1,11 +1,51 @@ name: semi-iso-version: 0.5.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@!- .- See first "Control.Lens.SemiIso" for semi-isomoprhisms.- After that look at "Data.SemiIsoFunctor".+version: 1.0.0.0+synopsis: Weakened partial isomorphisms, reversible computations.+description: + Semi-isomorphisms are partial isomorphisms with weakened iso laws. They are a basic+ building block of reversible computations. And they work with Iso and Prism from @lens@!+ .+ The module "Control.Lens.SemiIso" defines semi-isomorphisms and provides some+ basic semi-isos and combinators. A @SemiIso' a b@ can be applied in both directions+ to get a @a -> Either String b@ and @b -> Either String a@. SemiIsos can be composed+ with Isos and Prisms (to get another SemiIso). Isos and Prisms can be directly+ used as SemiIsos.+ .+ Semi-isomorphisms obey weaker laws then isomorphisms. We require only+ .+ > apply f >=> unapply f >=> apply f = apply f+ > unapply f >=> apply f >=> unapply f = unapply f+ .+ instead of+ .+ > apply f >=> unapply f = f+ > unapply f >=> apply f = f+ .+ Modules "Control.SIArrow" and "Control.Category.Structures" define an @Arrow@-like class+ hierarchy. Unfortunately "Control.Arrow" cannot be used, as it is too restrictive (the+ dreaded @arr@).++ SIArrow abstracts categories of reversible computations (with reversible side effects). In+ the case of parsing and pretty-printing using the "syntax" library if we have an arrow+ @SIArrow cat => cat a b@ then we can:+ .+ * Evaluate it from left to right, turning a value of type @a@ into a value of type @b@,+ with the side effect of consuming a sequence. (Parsing)+ .+ * Evaluate it from right to left, turning a value of type @b@ into a value of type @a@,+ with the side effect of generating a sequence. (Pretty-printing)+ .+ In the particular case of parsing/pretty-printing the type @a@ will be usually @()@, e.g.+ we just produce a value during parsing and just consume a value during pretty-printing.+ To support this style we define a functor and applicative structure on @cat () b@, for example+ '/*/' (equivalent of '<*>') has type @(\/*\/) :: SIArrow cat => cat () a -> cat () b -> cat () (a, b)@.+ .+ When more power then applicative is needed - for example when the syntax depends on the+ parsed value - we turn back to arrow composition.+ .+ Module "Control.Category.Reader" defines a Reader category transformer. It is like a monad+ transformer, but for categories. The next version will include some more transformers and+ mtl-style classes. license: MIT license-file: LICENSE author: Paweł Nowak@@ -22,9 +62,10 @@ library exposed-modules: Control.Lens.SemiIso Control.Lens.Internal.SemiIso- Data.SemiIsoFunctor- Data.SemiIsoFunctor.Wrapped+ Control.SIArrow+ Control.Category.Reader+ Control.Category.Structures Data.Profunctor.Exposed- build-depends: base >= 4 && < 5, profunctors, transformers, lens, tuple-morph+ build-depends: base >= 4 && < 5, profunctors, transformers, lens, tuple-morph, semigroupoids default-language: Haskell2010 ghc-options: -Wall