{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE Safe #-}
{-# LANGUAGE TypeOperators #-}

module Data.Bifunctor.Functor
  ( (:->)
  , BifunctorFunctor(..)
  , BifunctorMonad(..)
  , biliftM
  , BifunctorComonad(..)
  , biliftW
  ) where

-- | Using parametricity as an approximation of a natural transformation in two arguments.
type (:->) p q = forall a b. p a b -> q a b
infixr 0 :->

class BifunctorFunctor t where
  bifmap :: (p :-> q) -> t p :-> t q

class BifunctorFunctor t => BifunctorMonad t where
  bireturn :: p :-> t p
  bibind   :: (p :-> t q) -> t p :-> t q
  bibind p :-> t q
f = t (t q) a b -> t q a b
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *).
BifunctorMonad t =>
t (t p) :-> t p
forall (p :: k -> k -> *). t (t p) :-> t p
bijoin (t (t q) a b -> t q a b)
-> (t p a b -> t (t q) a b) -> t p a b -> t q a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (p :-> t q) -> t p :-> t (t q)
forall {k} {k} {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorFunctor t =>
(p :-> q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(p :-> q) -> t p :-> t q
bifmap p a b -> t q a b
p :-> t q
f
  bijoin   :: t (t p) :-> t p
  bijoin = (t p :-> t p) -> t (t p) :-> t p
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorMonad t =>
(p :-> t q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(p :-> t q) -> t p :-> t q
bibind t p a b -> t p a b
t p :-> t p
forall a. a -> a
id
  {-# MINIMAL bireturn, (bibind | bijoin) #-}

biliftM :: BifunctorMonad t => (p :-> q) -> t p :-> t q
biliftM :: forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorMonad t =>
(p :-> q) -> t p :-> t q
biliftM p :-> q
f = (p :-> t q) -> t p :-> t q
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorMonad t =>
(p :-> t q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(p :-> t q) -> t p :-> t q
bibind (q a b -> t q a b
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *).
BifunctorMonad t =>
p :-> t p
forall (p :: k -> k -> *). p :-> t p
bireturn (q a b -> t q a b) -> (p a b -> q a b) -> p a b -> t q a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. p a b -> q a b
p :-> q
f)
{-# INLINE biliftM #-}

class BifunctorFunctor t => BifunctorComonad t where
  biextract :: t p :-> p
  biextend :: (t p :-> q) -> t p :-> t q
  biextend t p :-> q
f = (t p :-> q) -> t (t p) :-> t q
forall {k} {k} {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorFunctor t =>
(p :-> q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(p :-> q) -> t p :-> t q
bifmap t p a b -> q a b
t p :-> q
f (t (t p) a b -> t q a b)
-> (t p a b -> t (t p) a b) -> t p a b -> t q a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t p a b -> t (t p) a b
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *).
BifunctorComonad t =>
t p :-> t (t p)
forall (p :: k -> k -> *). t p :-> t (t p)
biduplicate
  biduplicate :: t p :-> t (t p)
  biduplicate =  (t p :-> t p) -> t p :-> t (t p)
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorComonad t =>
(t p :-> q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(t p :-> q) -> t p :-> t q
biextend t p a b -> t p a b
t p :-> t p
forall a. a -> a
id
  {-# MINIMAL biextract, (biextend | biduplicate) #-}

biliftW :: BifunctorComonad t => (p :-> q) -> t p :-> t q
biliftW :: forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorComonad t =>
(p :-> q) -> t p :-> t q
biliftW p :-> q
f = (t p :-> q) -> t p :-> t q
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *) (q :: k -> k -> *).
BifunctorComonad t =>
(t p :-> q) -> t p :-> t q
forall (p :: k -> k -> *) (q :: k -> k -> *).
(t p :-> q) -> t p :-> t q
biextend (p a b -> q a b
p :-> q
f (p a b -> q a b) -> (t p a b -> p a b) -> t p a b -> q a b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. t p a b -> p a b
forall {k} {k} (t :: (k -> k -> *) -> k -> k -> *)
       (p :: k -> k -> *).
BifunctorComonad t =>
t p :-> p
forall (p :: k -> k -> *). t p :-> p
biextract)
{-# INLINE biliftW #-}