@@ -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