packages feed

proton-0.0.2: src/Data/Profunctor/Arrow.hs

{-# LANGUAGE ConstraintKinds #-}
module Data.Profunctor.Arrow where

import qualified Control.Category as C
import qualified Control.Arrow as Arr
import Data.Profunctor
import Data.Profunctor.Cayley
import Data.Profunctor.Strong
import Data.Profunctor.Closed
import Data.Profunctor.Choice
import Data.Profunctor.Traversing
import Data.Profunctor.Mapping
import Data.Profunctor.Yoneda
import Data.Profunctor.Ran
import Data.Profunctor.Composition

import Data.Bifunctor.Biff
import Data.Bifunctor.Tannen
import Data.Bifunctor.Joker
import Data.Bifunctor.Product
import Control.Applicative hiding (WrappedArrow(..))


arr :: (Profunctor p, C.Category p) => (a -> b) -> p a b
arr f = rmap f C.id

-- | Split the input between the two argument profunctors and combine their output.
(***) :: (C.Category p, Strong p) => p b c -> p b' c' -> p (b, b') (c, c')
l *** r = first' l C.. second' r

-- | Fanout: send the input to both argument arrows and combine their output.
(&&&) :: (C.Category p, Strong p) => p b c -> p b c' -> p b (c, c')
l &&& r =  lmap (\x -> (x, x)) (l *** r)

-- | Precomposition with a pure function.
(^>>) :: (Profunctor p, C.Category p) => (b -> c) -> p c d -> p b d
f ^>> p = arr f C.>>> p

-- | Postcomposition with a pure function.
(>>^) :: (Profunctor p, C.Category p) => p b c -> (c -> d) -> p b d
p >>^ f = p C.>>> arr f

-- | Precomposition with a pure function (right-to-left variant).
(<<^) :: (Profunctor p, C.Category p) => p c d -> (b -> c) -> p b d
p <<^ f = p C.<<< arr f

-- | Postcomposition with a pure function (right-to-left variant).
(^<<) :: (Profunctor p, C.Category p) => (c -> d) -> p b c -> p b d
f ^<< p = arr f C.<<< p

(+++) :: (Choice p, C.Category p) => p b c -> p b' c' -> p (Either b b') (Either c c')
l +++ r = left' l C.<<< right' r

(|||) :: (Choice p, C.Category p) => p b d -> p c d -> p (Either b c) d
l ||| r = rmap (either id id) (l +++ r)

class Profunctor p => ProfunctorZero p where
  zeroProfunctor :: p a b

instance Alternative f => ProfunctorZero (Star f) where
  zeroProfunctor = Star (const empty)

instance (Monad m, Alternative m) => ProfunctorZero (Arr.Kleisli m) where
  zeroProfunctor = Arr.Kleisli (const empty)

instance Monoid r => ProfunctorZero (Forget r) where
  zeroProfunctor = Forget (const mempty)

instance (Applicative f, ProfunctorZero p) => ProfunctorZero (Cayley f p) where
  zeroProfunctor = Cayley (pure zeroProfunctor)

instance (Applicative f, ProfunctorZero p) => ProfunctorZero (Tannen f p) where
  zeroProfunctor = Tannen (pure zeroProfunctor)

instance (ProfunctorZero p) => ProfunctorZero (Tambara p) where
  zeroProfunctor = Tambara zeroProfunctor

instance (ProfunctorZero p) => ProfunctorZero (Closure p) where
  zeroProfunctor = Closure zeroProfunctor

instance (ProfunctorZero p) => ProfunctorZero (TambaraSum p) where
  zeroProfunctor = TambaraSum zeroProfunctor

instance (ProfunctorZero p) => ProfunctorZero (CofreeTraversing p) where
  zeroProfunctor = CofreeTraversing zeroProfunctor

instance (ProfunctorZero p) => ProfunctorZero (CofreeMapping p) where
  zeroProfunctor = CofreeMapping zeroProfunctor

instance (ProfunctorZero p) => ProfunctorZero (Yoneda p) where
  zeroProfunctor = Yoneda (\_ _ -> zeroProfunctor)

instance Alternative f => ProfunctorZero (Joker f) where
  zeroProfunctor = Joker empty

instance Arr.ArrowZero p => ProfunctorZero (WrappedArrow p) where
  zeroProfunctor = WrapArrow Arr.zeroArrow

instance ProfunctorZero p => ProfunctorZero (Codensity p) where
  zeroProfunctor = Codensity (const zeroProfunctor)

instance (ProfunctorZero p, ProfunctorZero q) => ProfunctorZero (Product p q) where
  zeroProfunctor = Pair zeroProfunctor zeroProfunctor

instance  (Profunctor p, ProfunctorZero q) => ProfunctorZero (Rift p q) where
  zeroProfunctor = Rift (const zeroProfunctor)

instance  (ProfunctorZero p, Functor f, Functor g) => ProfunctorZero (Biff p f g) where
  zeroProfunctor = Biff zeroProfunctor

class ProfunctorZero p => ProfunctorPlus p where
  (<+>) :: p a b -> p a b -> p a b

instance Alternative f => ProfunctorPlus (Star f) where
  Star f <+> Star g = Star (liftA2 (<|>) f g)

instance (Monad m, Alternative m) => ProfunctorPlus (Arr.Kleisli m) where
  Arr.Kleisli f <+> Arr.Kleisli g = Arr.Kleisli (liftA2 (<|>) f g)

instance Monoid r => ProfunctorPlus (Forget r) where
  Forget f <+> Forget g = Forget (liftA2 (<>) f g)

instance (Applicative f, ProfunctorPlus p) => ProfunctorPlus (Cayley f p) where
  Cayley f <+> Cayley g = Cayley (liftA2 (<+>) f g)

instance (Applicative f, ProfunctorPlus p) => ProfunctorPlus (Tannen f p) where
  Tannen f <+> Tannen g = Tannen (liftA2 (<+>) f g)

instance (ProfunctorPlus p) => ProfunctorPlus (Tambara p) where
  Tambara f <+> Tambara g = Tambara (f <+> g)

instance (ProfunctorPlus p) => ProfunctorPlus (Closure p) where
  Closure f <+> Closure g = Closure (f <+> g)

instance (ProfunctorPlus p) => ProfunctorPlus (TambaraSum p) where
  TambaraSum f <+> TambaraSum g = TambaraSum (f <+> g)

instance (ProfunctorPlus p) => ProfunctorPlus (CofreeTraversing p) where
  CofreeTraversing f <+> CofreeTraversing g = CofreeTraversing (f <+> g)

instance (ProfunctorPlus p) => ProfunctorPlus (CofreeMapping p) where
  CofreeMapping f <+> CofreeMapping g = CofreeMapping (f <+> g)

instance Alternative f => ProfunctorPlus (Joker f) where
  Joker f <+> Joker g = Joker (f <|> g)

instance Arr.ArrowPlus p => ProfunctorPlus (WrappedArrow p) where
  WrapArrow f <+> WrapArrow g = WrapArrow (f Arr.<+> g)

instance ProfunctorPlus p => ProfunctorPlus (Codensity p) where
  Codensity f <+> Codensity g = Codensity (liftA2 (<+>) f g)

instance (ProfunctorPlus p, ProfunctorPlus q) => ProfunctorPlus (Product p q) where
  Pair fl fr <+> Pair gl gr = Pair (fl <+> gl) (fr <+> gr)

instance  (Profunctor p, ProfunctorPlus q) => ProfunctorPlus (Rift p q) where
  Rift f <+> Rift g = Rift (liftA2 (<+>) f g)

instance  (ProfunctorPlus p, Functor f, Functor g) => ProfunctorPlus (Biff p f g) where
  Biff f <+> Biff g = Biff (f <+> g)

class Profunctor p => ProfunctorApply p where
  app :: p (p a b, a) b

instance Functor f => ProfunctorApply (Star f) where
  app = Star (\(Star f, a) -> f a)

instance ProfunctorApply (->) where
  app = Arr.app

instance Monad m => ProfunctorApply (Arr.Kleisli m) where
  app = Arr.app

instance ProfunctorApply (Forget r) where
  app = Forget (\(Forget f, a) -> f a)

instance (Arr.Arrow p, Arr.ArrowApply p) => ProfunctorApply (WrappedArrow p) where
  app = Arr.app

instance Alternative g => ProfunctorApply (Joker g) where
  app = Joker empty