module Pandora.Pattern.Functor.Extendable where

import Pandora.Core.Functor (type (:.), type (:=))
import Pandora.Core.Morphism ((%))
import Pandora.Pattern.Category (identity, (.))
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>)))

infixl 1 =>>
infixr 1 <<=, =<=, =>=

{- |
> When providing a new instance, you should ensure it satisfies the three laws:
> * Duplication interchange: comap (comap f) . duplicate ≡ duplicate . comap f
> * Extension interchange: extend f ≡ comap f . duplicate
-}

class Covariant t => Extendable t where
	{-# MINIMAL (=>>) #-}
	-- | Infix and flipped version of 'extend', the dual of '>>='
	(=>>) :: t a -> (t a -> b) -> t b

	-- | Flipped version of '>>=', the dual of '=<<'
	(<<=) :: (t a -> b) -> t a -> t b
	(<<=) = (t a -> (t a -> b) -> t b) -> (t a -> b) -> t a -> t b
forall a b c. (a -> b -> c) -> b -> a -> c
(%) t a -> (t a -> b) -> t b
forall (t :: * -> *) a b. Extendable t => t a -> (t a -> b) -> t b
(=>>)
	-- | Prefix and flipped version of '=>>', the dual of 'bind'
	extend :: (t a -> b) -> t a -> t b
	extend t a -> b
f t a
t = t a
t t a -> (t a -> b) -> t b
forall (t :: * -> *) a b. Extendable t => t a -> (t a -> b) -> t b
=>> t a -> b
f
	-- | Clone existing structure, the dual of 'join'
	duplicate :: t a -> t :. t := a
	duplicate t a
t = t a
t t a -> (t a -> t a) -> (t :. t) := a
forall (t :: * -> *) a b. Extendable t => t a -> (t a -> b) -> t b
=>> t a -> t a
forall (m :: * -> * -> *) a. Category m => m a a
identity
	-- | Right-to-left Cokleisli composition
	(=<=) :: (t b -> c) -> (t a -> b) -> t a -> c
	t b -> c
f =<= t a -> b
g = t b -> c
f (t b -> c) -> (t a -> t b) -> t a -> c
forall (m :: * -> * -> *) b c a.
Category m =>
m b c -> m a b -> m a c
. (t a -> b) -> t a -> t b
forall (t :: * -> *) a b. Extendable t => (t a -> b) -> t a -> t b
extend t a -> b
g
	-- | Left-to-right Cokleisli composition
	(=>=) :: (t a -> b) -> (t b -> c) -> t a -> c
	t a -> b
f =>= t b -> c
g = t b -> c
g (t b -> c) -> (t a -> t b) -> t a -> c
forall (m :: * -> * -> *) b c a.
Category m =>
m b c -> m a b -> m a c
. (t a -> b) -> t a -> t b
forall (t :: * -> *) a b. Extendable t => (t a -> b) -> t a -> t b
extend t a -> b
f

	-- | Experimental methods
	($=>>) :: Covariant u => (t a -> b) -> u :. t := a -> u :. t := b
	t a -> b
f $=>> (u :. t) := a
x = (t a -> (t a -> b) -> t b
forall (t :: * -> *) a b. Extendable t => t a -> (t a -> b) -> t b
=>> t a -> b
f) (t a -> t b) -> ((u :. t) := a) -> (u :. t) := b
forall (t :: * -> *) a b. Covariant t => (a -> b) -> t a -> t b
<$> (u :. t) := a
x
	(<<=$) :: Covariant u => u :. t := a -> (t a -> b) -> u :. t := b
	(u :. t) := a
x <<=$ t a -> b
f = (t a -> (t a -> b) -> t b
forall (t :: * -> *) a b. Extendable t => t a -> (t a -> b) -> t b
=>> t a -> b
f) (t a -> t b) -> ((u :. t) := a) -> (u :. t) := b
forall (t :: * -> *) a b. Covariant t => (a -> b) -> t a -> t b
<$> (u :. t) := a
x