kan-extensions-5.2.8: src/Data/Functor/Invariant/Day.hs
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE RankNTypes #-}
-----------------------------------------------------------------------------
-- |
-- Copyright : (C) 2018 Brian Mckenna
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : Edward Kmett <ekmett@gmail.com>
-- Stability : provisional
-- Portability : portable
--
-- The Day convolution of two invariant functors is an invariant
-- functor.
--
-- <http://ncatlab.org/nlab/show/Day+convolution>
----------------------------------------------------------------------------
module Data.Functor.Invariant.Day
( Day(..)
, day
, assoc, disassoc
, swapped
, intro1, intro2
, elim1, elim2
, trans1, trans2
, toContravariant, toCovariant
) where
import qualified Data.Functor.Contravariant.Day as Contravariant
import qualified Data.Functor.Day as Covariant
import Data.Functor.Identity
import Data.Functor.Invariant
-- | The Day convolution of two invariant functors.
data Day f g a = forall b c. Day (f b) (g c) (b -> c -> a) (a -> (b, c))
instance Invariant (Day f g) where
invmap f g (Day fb gc bca abc) = Day fb gc ((f .) . bca) (abc . g)
-- | Construct the Day convolution
day :: f a -> g b -> Day f g (a, b)
day fa gb = Day fa gb (,) id
-- | Day convolution provides a monoidal product. The associativity
-- of this monoid is witnessed by 'assoc' and 'disassoc'.
--
-- @
-- 'assoc' . 'disassoc' = 'id'
-- 'disassoc' . 'assoc' = 'id'
-- 'invmap' f g '.' 'assoc' = 'assoc' '.' 'invmap' f g
-- @
assoc :: Day f (Day g h) a -> Day (Day f g) h a
assoc (Day fb (Day gd he dec cde) bca abc) = flip (Day (Day fb gd (,) id) he) f g
where
f a =
let (b,c) = abc a
(d,e) = cde c
in ((b,d),e)
g (b,d) e =
bca b (dec d e)
-- | Day convolution provides a monoidal product. The associativity
-- of this monoid is witnessed by 'assoc' and 'disassoc'.
--
-- @
-- 'assoc' . 'disassoc' = 'id'
-- 'disassoc' . 'assoc' = 'id'
-- 'invmap' f g '.' 'disassoc' = 'disassoc' '.' 'invmap' f g
-- @
disassoc :: Day (Day f g) h a -> Day f (Day g h) a
disassoc (Day (Day fb gc deb bde) hd bca abc) = Day fb (Day gc hd (,) id) f g
where
f e (d,c) =
bca (deb e d) c
g a =
let (b,c) = abc a
(d,e) = bde b
in (d,(e,c))
-- | The monoid for 'Day' convolution on the cartesian monoidal structure is symmetric.
--
-- @
-- 'invmap' f g '.' 'swapped' = 'swapped' '.' 'invmap' f g
-- @
swapped :: Day f g a -> Day g f a
swapped (Day fb gc bca abc) = Day gc fb (flip bca) (\a -> let (b, c) = abc a in (c, b))
-- | 'Identity' is the unit of 'Day' convolution
--
-- @
-- 'intro1' '.' 'elim1' = 'id'
-- 'elim1' '.' 'intro1' = 'id'
-- @
intro1 :: f a -> Day Identity f a
intro1 fa = Day (Identity ()) fa (\_ a -> a) ((,) ())
-- | 'Identity' is the unit of 'Day' convolution
--
-- @
-- 'intro2' '.' 'elim2' = 'id'
-- 'elim2' '.' 'intro2' = 'id'
-- @
intro2 :: f a -> Day f Identity a
intro2 fa = Day fa (Identity ()) const (flip (,) ())
-- | 'Identity' is the unit of 'Day' convolution
--
-- @
-- 'intro1' '.' 'elim1' = 'id'
-- 'elim1' '.' 'intro1' = 'id'
-- @
elim1 :: Invariant f => Day Identity f a -> f a
elim1 (Day (Identity b) fc bca abc) = invmap (bca b) (snd . abc) fc
-- | 'Identity' is the unit of 'Day' convolution
--
-- @
-- 'intro2' '.' 'elim2' = 'id'
-- 'elim2' '.' 'intro2' = 'id'
-- @
elim2 :: Invariant f => Day f Identity a -> f a
elim2 (Day fb (Identity c) bca abc) = invmap (flip bca c) (fst . abc) fb
-- | Apply a natural transformation to the left-hand side of a Day convolution.
--
-- This respects the naturality of the natural transformation you supplied:
--
-- @
-- 'invmap' f g '.' 'trans1' fg = 'trans1' fg '.' 'invmap' f g
-- @
trans1 :: (forall x. f x -> g x) -> Day f h a -> Day g h a
trans1 fg (Day fb hc bca abc) = Day (fg fb) hc bca abc
-- | Apply a natural transformation to the right-hand side of a Day convolution.
--
-- This respects the naturality of the natural transformation you supplied:
--
-- @
-- 'invmap' f g '.' 'trans2' fg = 'trans2' fg '.' 'invmap' f g
-- @
trans2 :: (forall x. g x -> h x) -> Day f g a -> Day f h a
trans2 gh (Day fb gc bca abc) = Day fb (gh gc) bca abc
-- | Drop the covariant part of the Day convolution.
toContravariant :: Day f g a -> Contravariant.Day f g a
toContravariant (Day fb gc _ abc) = Contravariant.Day fb gc abc
-- | Drop the contravariant part of the Day convolution.
toCovariant :: Day f g a -> Covariant.Day f g a
toCovariant (Day fb gc bca _) = Covariant.Day fb gc bca