module Pandora.Paradigm.Primary.Functor.Endo where

import Pandora.Pattern.Semigroupoid ((.))
import Pandora.Pattern.Category (identity, (#))
import Pandora.Pattern.Functor.Invariant (Invariant ((<$<)))
import Pandora.Pattern.Functor.Divariant ((>->))
import Pandora.Pattern.Object.Semigroup (Semigroup ((+)))
import Pandora.Pattern.Object.Monoid (Monoid (zero))
import Pandora.Paradigm.Controlflow.Effect.Interpreted (Interpreted (Primary, run, unite, (||=)))
import Pandora.Paradigm.Primary.Algebraic.Exponential ()

newtype Endo a = Endo { Endo a -> a -> a
endo :: a -> a }

instance Interpreted Endo where
	type Primary Endo a = a -> a
	run :: Endo a -> Primary Endo a
run ~(Endo a -> a
x) = Primary Endo a
a -> a
x
	unite :: Primary Endo a -> Endo a
unite = Primary Endo a -> Endo a
forall a. (a -> a) -> Endo a
Endo

instance Invariant Endo where
	a -> b
f <$< :: (a -> b) -> (b -> a) -> Endo a -> Endo b
<$< b -> a
g = (b -> a
g (b -> a) -> (a -> b) -> (a -> a) -> b -> b
forall (left :: * -> * -> *) (right :: * -> * -> *)
       (target :: * -> * -> *) (v :: * -> * -> *) a b c d.
Divariant left right target v =>
left a b -> right c d -> target (v b c) (v a d)
>-> a -> b
f (Primary Endo a -> Primary Endo b) -> Endo a -> Endo b
forall (t :: * -> *) (u :: * -> *) a b.
(Interpreted t, Interpreted u) =>
(Primary t a -> Primary u b) -> t a -> u b
||=)

instance Semigroup (Endo a) where
	Endo a -> a
f + :: Endo a -> Endo a -> Endo a
+ Endo a -> a
g = (a -> a) -> Endo a
forall a. (a -> a) -> Endo a
Endo ((a -> a) -> Endo a) -> (a -> a) -> Endo a
forall (m :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# a -> a
g (a -> a) -> (a -> a) -> a -> a
forall (m :: * -> * -> *) b c a.
Semigroupoid m =>
m b c -> m a b -> m a c
. a -> a
f

instance Monoid (Endo a) where
	zero :: Endo a
zero = (a -> a) -> Endo a
forall a. (a -> a) -> Endo a
Endo a -> a
forall (m :: * -> * -> *) a. Category m => m a a
identity