Skip to content

Commit

Permalink
Fix documentation for SemiproductProfunctor
Browse files Browse the repository at this point in the history
  • Loading branch information
endgame committed Apr 10, 2023
1 parent 6b03c15 commit 888b302
Showing 1 changed file with 42 additions and 39 deletions.
81 changes: 42 additions & 39 deletions Data/Profunctor/Product/Class.hs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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 ()
Expand Down

0 comments on commit 888b302

Please sign in to comment.