module Pandora.Pattern.Functor.Bindable 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 one law:
> * Interchange: t >>= f = join (f <$> t)
-}

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

	-- | Flipped version of '>>=', the dual of '<<='
	(=<<) :: (a -> t b) -> t a -> t b
	(=<<) = (t a -> (a -> t b) -> t b) -> (a -> t b) -> t a -> t b
forall a b c. (a -> b -> c) -> b -> a -> c
(%) t a -> (a -> t b) -> t b
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
(>>=)
	-- | Prefix and flipped version of '>>=', the dual of 'extend'
	bind :: (a -> t b) -> t a -> t b
	bind a -> t b
f t a
t = t a
t t a -> (a -> t b) -> t b
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= a -> t b
f
	-- | Merge effects/contexts, the dual of 'duplicate'
	join :: t :. t := a -> t a
	join (t :. t) := a
t = (t :. t) := a
t ((t :. t) := a) -> (t a -> t a) -> t a
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= t a -> t a
forall (m :: * -> * -> *) a. Category m => m a a
identity
	-- | Left-to-right Kleisli composition
	(>=>) :: (a -> t b) -> (b -> t c) -> (a -> t c)
	a -> t b
f >=> b -> t c
g = \a
x -> a -> t b
f a
x t b -> (b -> t c) -> t c
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= b -> t c
g
	-- | Right-to-left Kleisli composition
	(<=<) :: (b -> t c) -> (a -> t b) -> (a -> t c)
	(<=<) = ((a -> t b) -> (b -> t c) -> a -> t c)
-> (b -> t c) -> (a -> t b) -> a -> t c
forall a b c. (a -> b -> c) -> b -> a -> c
(%) (a -> t b) -> (b -> t c) -> a -> t c
forall (t :: * -> *) a b c.
Bindable t =>
(a -> t b) -> (b -> t c) -> a -> t c
(>=>)

	-- | Experimental methods
	($>>=) :: Covariant u => (a -> t b) -> u :. t := a -> u :. t := b
	a -> t b
f $>>= (u :. t) := a
x = (t a -> (a -> t b) -> t b
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= a -> t 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

	(<>>=) :: (t b -> c) -> (a -> t b) -> t a -> c
	t b -> c
f <>>= a -> t b
g = t b -> c
f (t b -> c) -> (t a -> t b) -> t a -> c
forall (t :: * -> *) a b. Covariant t => (a -> b) -> t a -> t b
<$> (t a -> (a -> t b) -> t b
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= a -> t b
g)

instance Bindable ((->) e) where
	e -> a
f >>= :: (e -> a) -> (a -> e -> b) -> e -> b
>>= a -> e -> b
g = \e
x -> a -> e -> b
g (e -> a
f e
x) e
x