git.iko.soy/semi-iso-optics
on master help sign in
My God, it's full of arrows!
commit1dc6707e78a2af754b40ded628975acab360c662 authorPaweł Nowak <pawel834@gmail.com> dateThu 11 Dec 2014, 00:17 (12 years ago) parent4cc50cd
5 files changed+212−245
Control/Category/Reader.hs+42 Control/SIArrow.hs+166 Data/SemiIsoFunctor.hs−204 Data/SemiIsoFunctor/Wrapped.hs−37 semi-iso.cabal+4−4
Control/Category/Reader.hsnew file+42
@@ -0,0 +1,42 @@
1+{-# LANGUAGE FlexibleInstances #-}
2+{-# LANGUAGE TypeFamilies #-}
3+{- |
4+Module : Control.Category.Reader
5+Description : Reader category transformer.
6+Copyright : (c) Paweł Nowak
7+License : MIT
8+
9+Maintainer : Paweł Nowak <pawel834@gmail.com>
10+Stability : experimental
11+
12+Provides a Reader category transformer.
13+-}
14+module Control.Category.Reader (
15+ ReaderCT(..)
16+ ) where
17+
18+import Control.Category
19+import Control.SIArrow
20+import Prelude hiding (id, (.))
21+
22+newtype ReaderCT env cat a b = ReaderCT { runReaderCT :: env -> cat a b }
23+
24+instance CategoryTrans (ReaderCT env) where
25+ clift = ReaderCT . const
26+
27+instance Category cat => Category (ReaderCT env cat) where
28+ id = clift id
29+ ReaderCT f . ReaderCT g = ReaderCT $ \x -> f x . g x
30+
31+instance Products cat => Products (ReaderCT env cat) where
32+ ReaderCT f *** ReaderCT g = ReaderCT $ \x -> f x *** g x
33+
34+instance Coproducts cat => Coproducts (ReaderCT env cat) where
35+ ReaderCT f +++ ReaderCT g = ReaderCT $ \x -> f x +++ g x
36+
37+instance CategoryPlus cat => CategoryPlus (ReaderCT env cat) where
38+ cempty = clift cempty
39+ ReaderCT f /+/ ReaderCT g = ReaderCT $ \x -> f x /+/ g x
40+
41+instance SIArrow cat => SIArrow (ReaderCT env cat) where
42+ siarr = clift . siarr
Control/SIArrow.hsnew file+166
@@ -0,0 +1,166 @@
1+{-# LANGUAGE TypeFamilies #-}
2+{-# LANGUAGE PatternSynonyms #-}
3+{-# LANGUAGE ConstraintKinds #-}
4+{- |
5+Module : Control.SIArrow
6+Description : Semi-iso arrows.
7+Copyright : (c) Paweł Nowak
8+License : MIT
9+
10+Maintainer : Paweł Nowak <pawel834@gmail.com>
11+Stability : experimental
12+
13+It can be instantiated by both covariant (like Parser) and contravariant
14+(like Printer) functors. Therefore it can be used as a common interface to unify
15+parsing and pretty printing.
16+-}
17+module Control.SIArrow where
18+
19+import Control.Arrow (Kleisli(..))
20+import qualified Control.Arrow as BadArrow
21+import Control.Category
22+import Control.Lens.Cons
23+import Control.Lens.Empty
24+import Control.Lens.SemiIso
25+import Control.Monad
26+import Data.Tuple.Morph
27+import Prelude hiding (id, (.))
28+
29+infixr 3 ***
30+infixr 2 +++
31+infixl 3 /+/
32+infixr 1 ^>>, >>^
33+infixr 1 ^<<, <<^
34+infixl 4 /$/, /$~, ~$/, ~$~
35+infixl 5 /*/, */, /*
36+
37+-- Categories.
38+
39+class Category cat => Products cat where
40+ first :: cat a b -> cat (a, c) (b, c)
41+ first a = a *** id
42+
43+ second :: cat a b -> cat (c, a) (c, b)
44+ second a = id *** a
45+
46+ (***) :: cat a b -> cat c d -> cat (a, c) (b, d)
47+ a *** b = first a >>> second b
48+
49+class Category cat => Coproducts cat where
50+ left :: cat a b -> cat (Either a c) (Either b c)
51+ left a = a +++ id
52+
53+ right :: cat a b -> cat (Either c a) (Either c b)
54+ right a = id +++ a
55+
56+ (+++) :: cat a b -> cat c d -> cat (Either a c) (Either b d)
57+ a +++ b = left a >>> right b
58+
59+class Category cat => CategoryPlus cat where
60+ cempty :: cat a b
61+ (/+/) :: cat a b -> cat a b -> cat a b
62+
63+class (Products cat, Coproducts cat, CategoryPlus cat) => SIArrow cat where
64+ siarr :: ASemiIso' a b -> cat a b
65+
66+ sipure :: ASemiIso' b a -> cat a b
67+ sipure = siarr . rev
68+
69+ sisome :: cat () b -> cat () [b]
70+ sisome v = _Cons /$/ v /*/ simany v
71+
72+ simany :: cat () b -> cat () [b]
73+ simany v = sisome v /+/ sipure _Empty
74+
75+class CategoryTrans t where
76+ clift :: Category cat => cat a b -> t cat a b
77+
78+-- Kleisli instances.
79+
80+instance Monad m => Products (Kleisli m) where
81+ (***) = (BadArrow.***)
82+
83+instance Monad m => Coproducts (Kleisli m) where
84+ (+++) = (BadArrow.+++)
85+
86+instance MonadPlus m => CategoryPlus (Kleisli m) where
87+ cempty = BadArrow.zeroArrow
88+ (/+/) = (BadArrow.<+>)
89+
90+instance MonadPlus m => SIArrow (Kleisli m) where
91+ siarr ai = Kleisli $ either fail return . apply ai
92+
93+(^>>) :: SIArrow cat => ASemiIso' a b -> cat b c -> cat a c
94+f ^>> a = a . siarr f
95+
96+(>>^) :: SIArrow cat => cat a b -> ASemiIso' b c -> cat a c
97+a >>^ f = siarr f . a
98+
99+(^<<) :: SIArrow cat => ASemiIso' b c -> cat a b -> cat a c
100+f ^<< a = siarr f . a
101+
102+(<<^) :: SIArrow cat => cat b c -> ASemiIso' a b -> cat a c
103+a <<^ f = a . siarr f
104+
105+(/$/) :: SIArrow cat => ASemiIso' b' b -> cat a b -> cat a b'
106+ai /$/ f = sipure ai . f
107+
108+-- | > ai /$~ f = ai . morphed /$/ f
109+--
110+-- This operator handles all the hairy stuff with uncurried application:
111+-- it reassociates the argument tuple and removes unnecessary (or adds necessary)
112+-- units to match the function type. You don't have to use @/*@ and @*/@ with this
113+-- operator.
114+(/$~) :: (SIArrow cat, HFoldable b', HFoldable b,
115+ HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b)
116+ => ASemiIso' a b' -> cat c b -> cat c a
117+ai /$~ h = cloneSemiIso ai . morphed /$/ h
118+
119+-- | > ai ~$/ f = morphed . ai /$/ f
120+(~$/) :: (SIArrow cat, HFoldable a', HFoldable a,
121+ HUnfoldable a', HUnfoldable a, Rep a' ~ Rep a)
122+ => ASemiIso' a' b -> cat c b -> cat c a
123+ai ~$/ h = morphed . cloneSemiIso ai /$/ h
124+
125+-- | > ai ~$~ f = morphed . ai . morphed /$/ f
126+(~$~) :: (SIArrow cat,
127+ HFoldable a, HUnfoldable a,
128+ HFoldable b, HUnfoldable b,
129+ HFoldable b', HUnfoldable b',
130+ Rep b' ~ Rep b, Rep b' ~ Rep a)
131+ => ASemiIso b' b' b' b' -> cat c b -> cat c a
132+ai ~$~ h = morphed . cloneSemiIso ai . morphed /$/ h
133+
134+(/*/) :: SIArrow cat => cat () b -> cat () c -> cat () (b, c)
135+a /*/ b = unit ^>> (a *** b)
136+
137+(/*) :: SIArrow cat => cat () a -> cat () () -> cat () a
138+f /* g = unit /$/ f /*/ g
139+
140+(*/) :: SIArrow cat => cat () () -> cat () a -> cat () a
141+f */ g = unit . swapped /$/ f /*/ g
142+
143+sifail :: SIArrow cat => String -> cat a b
144+sifail = siarr . alwaysFailing
145+
146+-- | Provides an error message in the case of failure.
147+(/?/) :: SIArrow cat => cat a b -> String -> cat a b
148+f /?/ msg = f /+/ sifail msg
149+
150+-- | Equivalent of 'sequence'.
151+sisequence :: SIArrow cat => [cat () a] -> cat () [a]
152+sisequence [] = sipure _Empty
153+sisequence (x:xs) = _Cons /$/ x /*/ sisequence xs
154+
155+-- | Equivalent of 'sequence_', restricted to units.
156+sisequence_ :: SIArrow cat => [cat () ()] -> cat () ()
157+sisequence_ [] = sipure _Empty
158+sisequence_ (x:xs) = unit /$/ x /*/ sisequence_ xs
159+
160+-- | Equivalent of 'replicateM'.
161+sireplicate :: SIArrow cat => Int -> cat () a -> cat () [a]
162+sireplicate n f = sisequence (replicate n f)
163+
164+-- | Equivalent of 'replicateM_', restricted to units.
165+sireplicate_ :: SIArrow cat => Int -> cat () () -> cat () ()
166+sireplicate_ n f = sisequence_ (replicate n f)
Data/SemiIsoFunctor.hsdeleted−204
@@ -1,204 +0,0 @@
1−{-# LANGUAGE TypeFamilies #-}
2−{-# LANGUAGE PatternSynonyms #-}
3−{- |
4−Module : Data.SemiIsoFunctor
5−Description : Functors from the category of semi-isomoprihsms to Hask.
6−Copyright : (c) Paweł Nowak
7−License : MIT
8−
9−Maintainer : Paweł Nowak <pawel834@gmail.com>
10−Stability : experimental
11−
12−Defines a functor from the category of semi-isomoprihsms to Hask.
13−
14−It can be instantiated by both covariant (like Parser) and contravariant
15−(like Printer) functors. Therefore it can be used as a common interface to unify
16−parsing and pretty printing.
17−-}
18−module Data.SemiIsoFunctor where
19−
20−import Control.Lens.Cons
21−import Control.Lens.Empty
22−import Control.Lens.SemiIso
23−import Data.Tuple.Morph
24−
25−infixl 3 /|/, /?/
26−infixl 4 /$/, ~$/, /$~, ~$~
27−infixl 5 /*/, /*, */
28−infixl 1 //=
29−infixr 1 =//
30−
31−-- | A functor from the category of semi-isomorphisms to Hask. We can think of it as
32−-- if it was both covariant and contravariant in its single argument.
33−--
34−-- The contravariant map is used by default to provide compatibility with
35−-- Prisms (otherwise you would have to reverse them in most cases).
36−--
37−-- This is really a pair of functors @F : SemiIso -> Hask@,
38−-- @G : SemiIso^op -> Hask@ satisfying:
39−--
40−-- > F(X) = G(X)
41−-- > F(f) = G(f^-1)
42−--
43−-- Instances should satisfy laws:
44−--
45−-- [/functoriality/]
46−--
47−-- prop> simap id = id
48−-- prop> simap (f . g) = simap g . simap f
49−--
50−-- [/inverse/]
51−--
52−-- prop> simap f = simapCo (rev f)
53−class SemiIsoFunctor f where
54− -- | The contravariant map.
55− simap :: ASemiIso' a b -> f b -> f a
56− simap = simapCo . rev
57−
58− -- | The covariant map.
59− simapCo :: ASemiIso' a b -> f a -> f b
60− simapCo = simap . rev
61−
62− {-# MINIMAL simap | simapCo #-}
63−
64−-- | A infix operator for 'simap'.
65−(/$/) :: SemiIsoFunctor f => ASemiIso' a b -> f b -> f a
66−(/$/) = simap
67−
68−-- | > ai /$~ f = ai . morphed /$/ f
69−--
70−-- This operator handles all the hairy stuff with uncurried application:
71−-- it reassociates the argument tuple and removes unnecessary (or adds necessary)
72−-- units to match the function type. You don't have to use @/*@ and @*/@ with this
73−-- operator.
74−(/$~) :: (SemiIsoFunctor f, HFoldable b', HFoldable b,
75− HUnfoldable b', HUnfoldable b, Rep b' ~ Rep b)
76− => ASemiIso' a b' -> f b -> f a
77−ai /$~ h = cloneSemiIso ai . morphed /$/ h
78−
79−-- | > ai ~$/ f = morphed . ai /$/ f
80−(~$/) :: (SemiIsoFunctor f, HFoldable a', HFoldable a,
81− HUnfoldable a', HUnfoldable a, Rep a' ~ Rep a)
82− => ASemiIso' a' b -> f b -> f a
83−ai ~$/ h = morphed . cloneSemiIso ai /$/ h
84−
85−-- | > ai ~$~ f = morphed . ai . morphed /$/ f
86−(~$~) :: (SemiIsoFunctor f,
87− HFoldable a, HUnfoldable a,
88− HFoldable b, HUnfoldable b,
89− HFoldable b', HUnfoldable b',
90− Rep b' ~ Rep b, Rep b' ~ Rep a)
91− => ASemiIso b' b' b' b' -> f b -> f a
92−ai ~$~ h = morphed . cloneSemiIso ai . morphed /$/ h
93−
94−-- | An applicative semi-iso functor, i. e. a lax monoidal functor from @SemiIso@
95−-- to @Hask@.
96−--
97−-- Instances should satisfy laws:
98−--
99−-- [/homomorphism/]
100−--
101−-- prop> sipure f /*/ sipure g = sipure (f `prod` g)
102−--
103−-- [/associativity/]
104−--
105−-- prop> f /*/ (g /*/ h) = associated /$/ (f /*/ g) /*/ h
106−--
107−-- [/unitality/]
108−--
109−-- prop> siunit /*/ x = swapped . rev unit /$/ x
110−-- prop> x /*/ siunit = rev unit /$/ x
111−--
112−-- Additionally it should be consistent with the default implementation:
113−--
114−-- prop> sipure ai = ai /$/ siunit
115−-- prop> sipureCo ai = ai `simapCo` siunit
116−--
117−-- prop> f /* g = unit /$/ f /*/ g
118−-- prop> f */ g = unit . swapped /$/ f /*/ g
119−class SemiIsoFunctor f => SemiIsoApply f where
120− siunit :: f ()
121− siunit = sipure id
122−
123− sipure :: ASemiIso' a () -> f a
124− sipure ai = ai /$/ siunit
125−
126− sipureCo :: ASemiIso' () a -> f a
127− sipureCo ai = ai `simapCo` siunit
128−
129− (/*/) :: f a -> f b -> f (a, b)
130−
131− (/*) :: f a -> f () -> f a
132− f /* g = unit /$/ f /*/ g
133−
134− (*/) :: f () -> f b -> f b
135− f */ g = unit . swapped /$/ f /*/ g
136−
137− {-# MINIMAL (siunit | sipure), (/*/) #-}
138−
139−-- | Fails with a message.
140−sifail :: SemiIsoApply f => String -> f a
141−sifail msg = alwaysFailing msg /$/ siunit
142−
143−-- | Equivalent of 'Alternative' for 'SemiIsoFunctor'.
144−--
145−-- @f a@ should form a monoid with identity 'siempty' and binary
146−-- operation '/|/'.
147−class SemiIsoApply f => SemiIsoAlternative f where
148− siempty :: f a
149− (/|/) :: f a -> f a -> f a
150−
151− sisome :: f a -> f [a]
152− sisome v = _Cons /$/ v /*/ simany v
153−
154− simany :: f a -> f [a]
155− simany v = sisome v /|/ sipure _Empty
156−
157− {-# MINIMAL siempty, (/|/) #-}
158−
159−-- | Provides an error message in the case of failure.
160−(/?/) :: SemiIsoAlternative f => f a -> String -> f a
161−f /?/ msg = f /|/ sifail msg
162−
163−-- | An analogue of 'Monad' for 'SemiIsoFunctor'.
164−--
165−-- Because of the 'no throwing away' rule bind has to \"return\"
166−-- both @a@ and @b@.
167−class SemiIsoApply m => SemiIsoMonad m where
168− (//=) :: m a -> (a -> m b) -> m (a, b)
169− m //= f = swapped /$/ (f =// m)
170−
171− (=//) :: (b -> m a) -> m b -> m (a, b)
172− f =// m = swapped /$/ (m //= f)
173−
174− {-# MINIMAL (//=) | (=//) #-}
175−
176−-- | A SemiIsoMonad with fixed point operator.
177−class SemiIsoMonad m => SemiIsoFix m where
178− sifix :: (a -> m a) -> m a
179− sifix f = dup /$/ (f =//= f)
180− where dup = semiIso (\a -> Right (a, a)) (Right . fst)
181−
182− -- | Fixed point combined with bind, it's so symmetric!
183− (=//=) :: (a -> m b) -> (b -> m a) -> m (a, b)
184− f =//= g = sifix (\(a, b) -> g b /*/ f a)
185−
186− {-# MINIMAL sifix | (=//=) #-}
187−
188−-- | Equivalent of 'sequence'.
189−sisequence :: SemiIsoApply f => [f a] -> f [a]
190−sisequence [] = sipure _Empty
191−sisequence (x:xs) = _Cons /$/ x /*/ sisequence xs
192−
193−-- | Equivalent of 'sequence_', restricted to units.
194−sisequence_ :: SemiIsoApply f => [f ()] -> f ()
195−sisequence_ [] = sipure _Empty
196−sisequence_ (x:xs) = unit /$/ x /*/ sisequence_ xs
197−
198−-- | Equivalent of 'replicateM'.
199−sireplicate :: SemiIsoApply f => Int -> f a -> f [a]
200−sireplicate n f = sisequence (replicate n f)
201−
202−-- | Equivalent of 'replicateM_', restricted to units.
203−sireplicate_ :: SemiIsoApply f => Int -> f () -> f ()
204−sireplicate_ n f = sisequence_ (replicate n f)
Data/SemiIsoFunctor/Wrapped.hsdeleted−37
@@ -1,37 +0,0 @@
1−{-# LANGUAGE FlexibleInstances #-}
2−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{- |
4−Module : Data.SemiIsoFunctor.Wrapped
5−Description : SemiIso instances for wrapped monads.
6−Copyright : (c) Paweł Nowak
7−License : MIT
8−
9−Maintainer : Paweł Nowak <pawel834@gmail.com>
10−Stability : experimental
11−
12−Every monad (with fail) is a SemiIsoMonad.
13−-}
14−module Data.SemiIsoFunctor.Wrapped where
15−
16−import Control.Applicative
17−import Control.Lens.SemiIso
18−import Control.Monad
19−import Data.SemiIsoFunctor
20−
21−-- | A wrapped covariant functor.
22−newtype WrappedCovariant m a = WrappedCovariant { runCovariant :: m a }
23− deriving (Functor, Applicative, Alternative, Monad)
24−
25−instance Monad m => SemiIsoFunctor (WrappedCovariant m) where
26− simapCo ai m = m >>= either fail return . apply ai
27−
28−instance Monad m => SemiIsoApply (WrappedCovariant m) where
29− sipure ai = either fail return (unapply ai ())
30− f /*/ g = liftM2 (,) f g
31−
32−instance (Monad m, Alternative m) => SemiIsoAlternative (WrappedCovariant m) where
33− siempty = empty
34− f /|/ g = f <|> g
35−
36−instance Monad m => SemiIsoMonad (WrappedCovariant m) where
37− f //= g = f >>= (\x -> g x >>= \y -> return (x, y))
semi-iso.cabal+4−4
@@ -1,11 +1,11 @@
11name: semi-iso
2−version: 0.5.0.0
2+version: 1.0.0.0
33synopsis: Weakened partial isomorphisms that work with lenses.
44description: Semi-isomorphisms are partial isomorphisms with weakened iso laws.
55 And they work with Iso and Prism from @lens@!
66 .
77 See first "Control.Lens.SemiIso" for semi-isomoprhisms.
8− After that look at "Data.SemiIsoFunctor".
8+ After that have a look at "Control.SIArrow".
99license: MIT
1010license-file: LICENSE
1111author: Paweł Nowak
@@ -22,8 +22,8 @@ source-repository head
2222library
2323 exposed-modules: Control.Lens.SemiIso
2424 Control.Lens.Internal.SemiIso
25− Data.SemiIsoFunctor
26− Data.SemiIsoFunctor.Wrapped
25+ Control.SIArrow
26+ Control.Category.Reader
2727 Data.Profunctor.Exposed
2828 build-depends: base >= 4 && < 5, profunctors, transformers, lens, tuple-morph
2929 default-language: Haskell2010