{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE Trustworthy #-}
module Data.Profunctor.Cayley where
import Control.Applicative
import Control.Arrow
import Control.Category
import Control.Comonad
import Data.Profunctor
import Data.Profunctor.Monad
import Data.Profunctor.Traversing
import Data.Profunctor.Unsafe
import Prelude hiding ((.), id)
newtype Cayley f p a b = Cayley { runCayley :: f (p a b) }
instance Functor f => ProfunctorFunctor (Cayley f) where
promap f (Cayley p) = Cayley (fmap f p)
instance (Functor f, Monad f) => ProfunctorMonad (Cayley f) where
proreturn = Cayley . return
projoin (Cayley m) = Cayley $ m >>= runCayley
instance Comonad f => ProfunctorComonad (Cayley f) where
proextract = extract . runCayley
produplicate (Cayley w) = Cayley $ extend Cayley w
instance (Functor f, Profunctor p) => Profunctor (Cayley f p) where
dimap f g = Cayley . fmap (dimap f g) . runCayley
lmap f = Cayley . fmap (lmap f) . runCayley
rmap g = Cayley . fmap (rmap g) . runCayley
w #. Cayley fp = Cayley $ fmap (w #.) fp
Cayley fp .# w = Cayley $ fmap (.# w) fp
instance (Functor f, Strong p) => Strong (Cayley f p) where
first' = Cayley . fmap first' . runCayley
second' = Cayley . fmap second' . runCayley
instance (Functor f, Costrong p) => Costrong (Cayley f p) where
unfirst (Cayley fp) = Cayley (fmap unfirst fp)
unsecond (Cayley fp) = Cayley (fmap unsecond fp)
instance (Functor f, Choice p) => Choice (Cayley f p) where
left' = Cayley . fmap left' . runCayley
right' = Cayley . fmap right' . runCayley
instance (Functor f, Cochoice p) => Cochoice (Cayley f p) where
unleft (Cayley fp) = Cayley (fmap unleft fp)
{-# INLINE unleft #-}
unright (Cayley fp) = Cayley (fmap unright fp)
{-# INLINE unright #-}
instance (Functor f, Closed p) => Closed (Cayley f p) where
closed = Cayley . fmap closed . runCayley
instance (Functor f, Traversing p) => Traversing (Cayley f p) where
traverse' = Cayley . fmap traverse' . runCayley
instance (Functor f, Mapping p) => Mapping (Cayley f p) where
map' = Cayley . fmap map' . runCayley
instance (Applicative f, Category p) => Category (Cayley f p) where
id = Cayley $ pure id
Cayley fpbc . Cayley fpab = Cayley $ liftA2 (.) fpbc fpab
instance (Applicative f, Arrow p) => Arrow (Cayley f p) where
arr f = Cayley $ pure $ arr f
first = Cayley . fmap first . runCayley
second = Cayley . fmap second . runCayley
Cayley ab *** Cayley cd = Cayley $ liftA2 (***) ab cd
Cayley ab &&& Cayley ac = Cayley $ liftA2 (&&&) ab ac
instance (Applicative f, ArrowChoice p) => ArrowChoice (Cayley f p) where
left = Cayley . fmap left . runCayley
right = Cayley . fmap right . runCayley
Cayley ab +++ Cayley cd = Cayley $ liftA2 (+++) ab cd
Cayley ac ||| Cayley bc = Cayley $ liftA2 (|||) ac bc
instance (Applicative f, ArrowLoop p) => ArrowLoop (Cayley f p) where
loop = Cayley . fmap loop . runCayley
instance (Applicative f, ArrowZero p) => ArrowZero (Cayley f p) where
zeroArrow = Cayley $ pure zeroArrow
instance (Applicative f, ArrowPlus p) => ArrowPlus (Cayley f p) where
Cayley f <+> Cayley g = Cayley (liftA2 (<+>) f g)
mapCayley :: (forall a. f a -> g a) -> Cayley f p x y -> Cayley g p x y
mapCayley f (Cayley g) = Cayley (f g)