packages feed

squares-0.2.1: src/Data/Profunctor/Kan/Square.hs

{-# LANGUAGE DataKinds, RankNTypes, GADTs #-}
-----------------------------------------------------------------------------
-- |
-- Module      :  Data.Profunctor.Kan.Square
-- License     :  BSD-style (see the file LICENSE)
-- Maintainer  :  sjoerd@w3future.com
--
-----------------------------------------------------------------------------
module Data.Profunctor.Kan.Square where

import Data.Square
import Data.Profunctor
import Data.Profunctor.Composition
import Data.Functor.Compose.List

-- | The right Kan extension of a profunctor @p@ along a profunctor @j@.
newtype Ran j p a b = Ran { runRan :: forall c. j c a -> p c b }
instance Profunctor p => Functor (Ran j p a) where
  fmap f (Ran jp) = Ran $ rmap f . jp
instance (Profunctor j, Profunctor p) => Profunctor (Ran j p) where
  lmap l (Ran jp) = Ran $ jp . rmap l
  rmap r (Ran jp) = Ran $ rmap r . jp
  dimap l r (Ran jp) = Ran $ rmap r . jp . rmap l

-- |
-- > +-----+
-- > j-\   |
-- > |  @--p
-- > R-/   |
-- > +-----+
ranSquare :: (Profunctor j, Profunctor p) => Square '[j, Ran j p] '[p] '[] '[]
ranSquare = mkSquare $ \(Procompose r j) -> runRan r j

-- |
-- > +-----+     +-----+
-- > j-\   |     |     |
-- > |  @--p ==> q--@--R
-- > q-/   |     |     |
-- > +-----+     +-----+
--
-- Any square like the one on the left factors through 'ranSquare'.
-- 'ranFactor' gives the remaining square.
ranFactor
  :: (Profunctor j, Profunctor p, Profunctor q)
  => Square '[j, q] '[p] '[] '[] -> Square '[q] '[Ran j p] '[] '[]
ranFactor sq = mkSquare $ \q -> Ran $ \j -> runSquare sq (Procompose q j)

-- |
-- > +-----+
-- > R-\   |
-- > |  @--p
-- > j-/   |
-- > +-----+
riftSquare :: (Profunctor j, Profunctor p) => Square '[Rift j p, j] '[p] '[] '[]
riftSquare = mkSquare $ \(Procompose j r) -> runRift r j

-- |
-- > +-----+     +-----+
-- > q-\   |     |     |
-- > |  @--p ==> q--@--R
-- > j-/   |     |     |
-- > +-----+     +-----+
--
-- Any square like the one on the left factors through 'riftSquare'.
-- 'riftFactor' gives the remaining square.
riftFactor
  :: (Profunctor j, Profunctor p, Profunctor q)
  => Square '[q, j] '[p] '[] '[] -> Square '[q] '[Rift j p] '[] '[]
riftFactor sq = mkSquare $ \q -> Rift $ \j -> runSquare sq (Procompose j q)