From 888b302f0e6ddf603ceaf9317c9118dfceb454d8 Mon Sep 17 00:00:00 2001 From: Jack Kelly Date: Mon, 10 Apr 2023 14:31:35 +1000 Subject: [PATCH] Fix documentation for `SemiproductProfunctor` --- Data/Profunctor/Product/Class.hs | 81 +++++++++++++++++--------------- 1 file changed, 42 insertions(+), 39 deletions(-) diff --git a/Data/Profunctor/Product/Class.hs b/Data/Profunctor/Product/Class.hs index a8965a4..5471ebb 100644 --- a/Data/Profunctor/Product/Class.hs +++ b/Data/Profunctor/Product/Class.hs @@ -5,57 +5,48 @@ import qualified Data.Profunctor as Profunctor import Data.Semigroup (Semigroup, (<>)) import Data.Void (Void, absurd) --- | 'ProductProfunctor' is a generalization of --- 'Control.Applicative.Applicative'. --- It has the usual 'Control.Applicative.Applicative' "output" --- (covariant) parameter on the right. Additionally it has an "input" --- (contravariant) type parameter on the left. + +-- | A 'SemiproductProfunctor' is a profunctor whose input and output +-- values can be combined with @(,)@. ('***!') makes this most +-- obvious, though ('****') and 'liftP2' are equivalent in power. -- --- The methods for 'ProductProfunctor' correspond closely to those for --- 'Control.Applicative.Applicative' as laid out in the following --- table. --- The only difference between them is that the 'ProductProfunctor' --- has a contravariant type parameter on the left. We can use the --- contravariant to compose them in nice ways as described at --- "Data.Profunctor.Product". +-- A value of type @p a x@ with an @instance 'SemiproductProfunctor' p@ +-- often represents some sort of process for turning @a@s into @x@s +-- that can be "laid out side-by-side" with other similar values of +-- @p@ to form "wider" processes. For example, if I have three such +-- encoders: -- -- @ --- | Correspondence between Applicative and ProductProfunctor --- | --- | 'Control.Applicative.Applicative' f 'ProductProfunctor' p --- | --- | 'Control.Applicative.pure' 'purePP' --- | :: b -> f b :: b -> p a b --- | --- | ('Control.Applicative.<$>') ('Data.Profunctor.Product.***$') --- | :: (b -> b') :: (b -> b') --- | -> f b -> p a b --- | -> f b' -> p a b' --- | --- | ('Control.Applicative.<*>') ('****') --- | :: f (b -> b') :: p a (b -> b') --- | -> f b -> p a b --- | -> f b' -> p a b' +-- p :: p a x -- a process for turning as into xs +-- q :: p b y -- a process for turning bs into ys +-- r :: p c z -- a process for turning cs into zs -- @ -- --- It's easy to make instances of 'ProductProfunctor'. Just make --- instances +-- I can then combine them using 'p3' to get: -- -- @ --- instance 'Profunctor' MyProductProfunctor where --- ... --- --- instance 'Control.Applicative.Applicative' (MyProductProfunctor a) where --- ... +-- -- a process for turning (a, b, c)s into (x, y, z)s +-- p3 p q r :: p (a, b, c) (x, y, z) -- @ -- --- and then write +-- You would typically compose 'ProductProfunctor's using +-- 'Profunctor'\'s 'lmap', '<$>' \/ 'fmap', and @Apply@ \/ +-- 'Applicative'\'s 'pure' and @\<.\>@ \/ @('<*>')@. +-- +-- You can often write these instances mechancially: -- -- @ --- instance 'ProductProfunctor' MyProductProfunctor where --- 'purePP' = 'Control.Applicative.pure' --- ('****') = ('Control.Applicative.<*>') +-- instance SemiproductProfunctor P where +-- (****) = (\<.\>) -- If you have `instance Apply (P a)` +-- (****) = ('<*>') -- If you have `instance 'Applicative' (P a)` -- @ +-- +-- Laws: +-- +-- * @('***!')@ is associative up to tuple rearrangement. +-- +-- * If @p@ is also a 'SemisumProfunctor', @('***!')@ should +-- distribute over @('+++!')@ up to tuple/@Either@ rearrangement. class Profunctor p => SemiproductProfunctor p where (***!) :: p a b -> p a' b' -> p (a, a') (b, b') f ***! g = liftP2 (,) (Profunctor.lmap fst f) (Profunctor.lmap snd g) @@ -90,6 +81,18 @@ divisedP :: (SemiproductProfunctor p, Semigroup x) => p a x -> p b x -> p (a, b) x divisedP = diviseP id +-- | 'SemiproductProfunctor's with a unit. +-- +-- If you have an 'Applicative' instance for @P a@, you can write this +-- instance mechanically: +-- +-- @ +-- instance ProductProfunctor p where +-- pureP = pure +-- @ +-- +-- Law: @unitP@ is an identity for @('***!')@, up to tuple +-- rearrangement. class SemiproductProfunctor p => ProductProfunctor p where -- | Unit for @('***!')@. unitP :: p x ()