git.iko.soy/semi-iso-optics
on master help sign in
Reintroduce 'prod'. Added laws for SemiIsoApply and improved comments.
commit0e68b49fe0bb728c2ea82f905022d3258479fe3e authorPaweł Nowak <pawel834@gmail.com> dateSat 29 Nov 2014, 20:29 (12 years ago) parentfaf5e0b
3 files changed+47−16
Control/Lens/SemiIso.hs+5 Data/Profunctor/Exposed.hs+4−4 Data/SemiIsoFunctor.hs+38−12
Control/Lens/SemiIso.hs+5
@@ -75,6 +75,7 @@ module Control.Lens.SemiIso (
7575
7676 -- * Transforming semi-isos.
7777 rev,
78+ prod,
7879 elimFirst,
7980 elimSecond,
8081 attempt,
@@ -255,6 +256,10 @@ _Negative = semiIso f g
255256rev :: ASemiIso s t a b -> SemiIso b a t s
256257rev ai = withSemiIso ai $ \l r -> semiIso r l
257258
259+-- | A product of semi-isos.
260+prod :: ASemiIso' s a -> ASemiIso' t b -> SemiIso' (s, t) (a, b)
261+prod a b = runSemiIso (reifySemiIso a *** reifySemiIso b)
262+
258263-- | Uses an @SemiIso' a ()@ to construct a @SemiIso' (a, b) b@,
259264-- i.e. eliminates the first pair element.
260265elimFirst :: ASemiIso' s () -> SemiIso' (s, t) t
Data/Profunctor/Exposed.hs+4−4
@@ -17,10 +17,10 @@ import Data.Profunctor
1717--
1818-- Should obey laws:
1919--
20−-- > merge . rmap return = id
21−-- > lmap return . expose = id
22−-- > rmap (>>= f) = merge . rmap (fmap f)
23−-- > lmap (fmap f) . expose = expose . lmap f
20+-- prop> merge . rmap return = id
21+-- prop> lmap return . expose = id
22+-- prop> rmap (>>= f) = merge . rmap (fmap f)
23+-- prop> lmap (fmap f) . expose = expose . lmap f
2424class (Monad m, Profunctor p) => Exposed m p | p -> m where
2525 expose :: p a b -> p (m a) b
2626 merge :: p a (m b) -> p a b
Data/SemiIsoFunctor.hs+38−12
@@ -29,19 +29,28 @@ infixl 5 /*/, /*, */
2929infixl 1 //=
3030infixr 1 =//
3131
32−-- | A functor from the category of semi-isomorphisms to Hask.
33−--
34−-- It is both covariant and contravariant in its single arugment.
32+-- | A functor from the category of semi-isomorphisms to Hask. We can think of it as
33+-- if it was both covariant and contravariant in its single argument.
3534--
3635-- The contravariant map is used by default to provide compatibility with
3736-- Prisms (otherwise you would have to reverse them in most cases).
3837--
38+-- This is really a pair of functors @F : SemiIso -> Hask@,
39+-- @G : SemiIso^op -> Hask@ satisfying:
40+--
41+-- > F(X) = G(X)
42+-- > F(f) = G(f^-1)
43+--
3944-- Instances should satisfy laws:
4045--
41−-- > simap id = id
42−-- > simap (f . g) = simap g . simap f
43−-- > simap = simapCo . fromSemi
44−-- > simapCo = simap . fromSemi
46+-- [/functoriality/]
47+--
48+-- prop> simap id = id
49+-- prop> simap (f . g) = simap g . simap f
50+--
51+-- [/inverse/]
52+--
53+-- prop> simap f = simapCo (rev f)
4554class SemiIsoFunctor f where
4655 -- | The contravariant map.
4756 simap :: ASemiIso' a b -> f b -> f a
@@ -83,14 +92,31 @@ ai ~$/ h = morphed . cloneSemiIso ai /$/ h
8392 => ASemiIso b' b' b' b' -> f b -> f a
8493ai ~$~ h = morphed . cloneSemiIso ai . morphed /$/ h
8594
86−-- | Equivalent of 'Applicative' for 'SemiIsoFunctor'.
87−--
88−-- However, this class implements uncurried application, unlike
89−-- 'Control.Applicative' which gives you curried application.
95+-- | An applicative semi-iso functor, i. e. a lax monoidal functor from @SemiIso@
96+-- to @Hask@.
9097--
9198-- Instances should satisfy laws:
9299--
93−-- > TODO (they should be fine)
100+-- [/homomorphism/]
101+--
102+-- prop> sipure f /*/ sipure g = sipure (f `prod` g)
103+--
104+-- [/associativity/]
105+--
106+-- prop> f /*/ (g /*/ h) = associated /$/ (f /*/ g) /*/ h
107+--
108+-- [/unitality/]
109+--
110+-- prop> siunit /*/ x = swapped . rev unit /$/ x
111+-- prop> x /*/ siunit = rev unit /$/ x
112+--
113+-- Additionally it should be consistent with the default implementation:
114+--
115+-- prop> sipure ai = ai /$/ siunit
116+-- prop> sipureCo ai = ai `simapCo` siunit
117+--
118+-- prop> f /* g = unit /$/ f /*/ g
119+-- prop> f */ g = unit . swapped /$/ f /*/ g
94120class SemiIsoFunctor f => SemiIsoApply f where
95121 siunit :: f ()
96122 siunit = sipure id