Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Derived by combining the covariant and contravariant versions of Day. Using this as a tensor gives us a combination of Applicative and Divisible, which seems useful for things like derivation of function pairs like parsers/printers.
- Loading branch information
1 parent
7aad431
commit 77d60ec
Showing
2 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,150 @@ | ||
{-# 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 |