module Pandora.Paradigm.Controlflow.Pipeline (Pipeline, await, yield, finish, impact, (=*=), pipeline) where

import Pandora.Pattern.Category (($), (.), (/))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Bindable (Bindable ((>>=)))
import Pandora.Paradigm.Primary.Functor.Function ((!), (!!))
import Pandora.Paradigm.Controlflow.Effect.Interpreted (Interpreted (Primary, run, unite))
import Pandora.Paradigm.Primary.Transformer.Continuation (Continuation (Continuation))

newtype Producer i t r = Producer { Producer i t r -> Consumer i t r -> t r
produce :: Consumer i t r -> t r }

instance Interpreted (Producer i t) where
	type Primary (Producer i t) a = Consumer i t a -> t a
	run :: Producer i t a -> Primary (Producer i t) a
run ~(Producer Consumer i t a -> t a
f) = Primary (Producer i t) a
Consumer i t a -> t a
f
	unite :: Primary (Producer i t) a -> Producer i t a
unite = Primary (Producer i t) a -> Producer i t a
forall k i (t :: k -> *) (r :: k).
(Consumer i t r -> t r) -> Producer i t r
Producer

newtype Consumer o t r = Consumer { Consumer o t r -> o -> Producer o t r -> t r
consume :: o -> Producer o t r -> t r }

instance Interpreted (Consumer o t) where
	type Primary (Consumer o t) a = o -> Producer o t a -> t a
	run :: Consumer o t a -> Primary (Consumer o t) a
run ~(Consumer o -> Producer o t a -> t a
f) = Primary (Consumer o t) a
o -> Producer o t a -> t a
f
	unite :: Primary (Consumer o t) a -> Consumer o t a
unite = Primary (Consumer o t) a -> Consumer o t a
forall k o (t :: k -> *) (r :: k).
(o -> Producer o t r -> t r) -> Consumer o t r
Consumer

newtype Pipe i o r t a = Pipe { Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe :: Producer i t r -> Consumer o t r -> t r }

type Pipeline i o t a r = Continuation r (Pipe i o r t) a

pause :: (() -> Pipe i o r t a) -> Producer i t r -> Producer o t r
pause :: (() -> Pipe i o r t a) -> Producer i t r -> Producer o t r
pause () -> Pipe i o r t a
next Producer i t r
ik = (Consumer o t r -> t r) -> Producer o t r
forall k i (t :: k -> *) (r :: k).
(Consumer i t r -> t r) -> Producer i t r
Producer ((Consumer o t r -> t r) -> Producer o t r)
-> (Consumer o t r -> t r) -> Producer o t r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \Consumer o t r
ok -> (Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
forall i o k (r :: k) (t :: k -> *) k (a :: k).
Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe (Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r)
-> Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
$ () -> Pipe i o r t a
next ()) Producer i t r
ik Consumer o t r
ok

suspend :: (i -> Pipe i o r t a) -> Consumer o t r -> Consumer i t r
suspend :: (i -> Pipe i o r t a) -> Consumer o t r -> Consumer i t r
suspend i -> Pipe i o r t a
next Consumer o t r
ok = (i -> Producer i t r -> t r) -> Consumer i t r
forall k o (t :: k -> *) (r :: k).
(o -> Producer o t r -> t r) -> Consumer o t r
Consumer ((i -> Producer i t r -> t r) -> Consumer i t r)
-> (i -> Producer i t r -> t r) -> Consumer i t r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \i
v Producer i t r
ik -> Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
forall i o k (r :: k) (t :: k -> *) k (a :: k).
Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe (Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r)
-> Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
/ i -> Pipe i o r t a
next i
v (Producer i t r -> Consumer o t r -> t r)
-> Producer i t r -> Consumer o t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
/ Producer i t r
ik (Consumer o t r -> t r) -> Consumer o t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
/ Consumer o t r
ok

-- | Take incoming value from pipeline
await :: Pipeline i o t i r
await :: Pipeline i o t i r
await = ((((->) ::|:. i) :. Pipe i o r t) := r) -> Pipeline i o t i r
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation (((((->) ::|:. i) :. Pipe i o r t) := r) -> Pipeline i o t i r)
-> ((((->) ::|:. i) :. Pipe i o r t) := r) -> Pipeline i o t i r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \i -> Pipe i o r t r
next -> (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe ((Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r)
-> (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \(Producer Consumer i t r -> t r
i) Consumer o t r
o -> Consumer i t r -> t r
i (Consumer i t r -> t r) -> Consumer i t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
/ (i -> Pipe i o r t r) -> Consumer o t r -> Consumer i t r
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(i -> Pipe i o r t a) -> Consumer o t r -> Consumer i t r
suspend i -> Pipe i o r t r
next Consumer o t r
o

-- | Give a value to the future consuming
yield :: o -> Pipeline i o t () r
yield :: o -> Pipeline i o t () r
yield o
v = ((((->) ::|:. ()) :. Pipe i o r t) := r) -> Pipeline i o t () r
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation (((((->) ::|:. ()) :. Pipe i o r t) := r) -> Pipeline i o t () r)
-> ((((->) ::|:. ()) :. Pipe i o r t) := r) -> Pipeline i o t () r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \() -> Pipe i o r t r
next -> (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe ((Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r)
-> (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t r
forall (m :: * -> * -> *). Category m => m ~~> m
$ \Producer i t r
i (Consumer o -> Producer o t r -> t r
o) -> o -> Producer o t r -> t r
o o
v (Producer o t r -> t r) -> Producer o t r -> t r
forall (m :: * -> * -> *). Category m => m ~~> m
/ (() -> Pipe i o r t r) -> Producer i t r -> Producer o t r
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(() -> Pipe i o r t a) -> Producer i t r -> Producer o t r
pause () -> Pipe i o r t r
next Producer i t r
i

-- | Pipeline that does nothing
finish :: Pointable t => Pipeline i o t () ()
finish :: Pipeline i o t () ()
finish = ((((->) ::|:. ()) :. Pipe i o () t) := ()) -> Pipeline i o t () ()
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation ((Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ()
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe (() :=> t
forall (t :: * -> *) a. Pointable t => a :=> t
point () t () -> Producer i t () -> Consumer o t () -> t ()
forall a b c. a -> b -> c -> a
!!) Pipe i o () t () -> (((->) ::|:. ()) :. Pipe i o () t) := ()
forall a b. a -> b -> a
!)

-- | Do some effectful computation within pipeline
impact :: Bindable t => t a -> Pipeline i o t a a
impact :: t a -> Pipeline i o t a a
impact t a
action = ((((->) ::|:. a) :. Pipe i o a t) := a) -> Pipeline i o t a a
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation (((((->) ::|:. a) :. Pipe i o a t) := a) -> Pipeline i o t a a)
-> ((((->) ::|:. a) :. Pipe i o a t) := a) -> Pipeline i o t a a
forall (m :: * -> * -> *). Category m => m ~~> m
$ \a -> Pipe i o a t a
next -> (Producer i t a -> Consumer o t a -> t a) -> Pipe i o a t a
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe ((Producer i t a -> Consumer o t a -> t a) -> Pipe i o a t a)
-> (Producer i t a -> Consumer o t a -> t a) -> Pipe i o a t a
forall (m :: * -> * -> *). Category m => m ~~> m
$ \Producer i t a
i Consumer o t a
o -> t a
action t a -> (a -> t a) -> t a
forall (t :: * -> *) a b. Bindable t => t a -> (a -> t b) -> t b
>>= \a
x -> Pipe i o a t a -> Producer i t a -> Consumer o t a -> t a
forall i o k (r :: k) (t :: k -> *) k (a :: k).
Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe (a -> Pipe i o a t a
next a
x) Producer i t a
i Consumer o t a
o

-- | Compose two pipelines into one
(=*=) :: forall i e o t . Pointable t => Pipeline i e t () () -> Pipeline e o t () () -> Pipeline i o t () ()
Pipeline i e t () ()
p =*= :: Pipeline i e t () ()
-> Pipeline e o t () () -> Pipeline i o t () ()
=*= Pipeline e o t () ()
q = ((((->) ::|:. ()) :. Pipe i o () t) := ()) -> Pipeline i o t () ()
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation (((((->) ::|:. ()) :. Pipe i o () t) := ())
 -> Pipeline i o t () ())
-> ((((->) ::|:. ()) :. Pipe i o () t) := ())
-> Pipeline i o t () ()
forall (m :: * -> * -> *). Category m => m ~~> m
$ \() -> Pipe i o () t ()
_ -> (Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ()
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe ((Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ())
-> (Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ()
forall (m :: * -> * -> *). Category m => m ~~> m
$ \Producer i t ()
i -> Pipe e o () t () -> Producer e t () -> Consumer o t () -> t ()
forall i o k (r :: k) (t :: k -> *) k (a :: k).
Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe (Pipe e o () t () -> Producer e t () -> Consumer o t () -> t ())
-> Pipe e o () t () -> Producer e t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *). Category m => m ~~> m
/ Pipeline e o t () () -> (((->) ::|:. ()) :. Pipe e o () t) := ()
forall (t :: * -> *) a. Interpreted t => t a -> Primary t a
run Pipeline e o t () ()
q () -> Pipe e o () t ()
forall b c d. b -> Pipe c d () t ()
end (Producer e t () -> Consumer o t () -> t ())
-> Producer e t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *). Category m => m ~~> m
/ (() -> Pipe i e () t ()) -> Producer i t () -> Producer e t ()
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(() -> Pipe i o r t a) -> Producer i t r -> Producer o t r
pause (Pipeline i e t () () -> (((->) ::|:. ()) :. Pipe i e () t) := ()
forall (t :: * -> *) a. Interpreted t => t a -> Primary t a
run Pipeline i e t () ()
p () -> Pipe i e () t ()
forall b c d. b -> Pipe c d () t ()
end Pipe i e () t () -> () -> Pipe i e () t ()
forall a b. a -> b -> a
!) Producer i t ()
i where

	end :: b -> Pipe c d () t ()
	end :: b -> Pipe c d () t ()
end b
_ = (Producer c t () -> Consumer d t () -> t ()) -> Pipe c d () t ()
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe (() :=> t
forall (t :: * -> *) a. Pointable t => a :=> t
point () t () -> Producer c t () -> Consumer d t () -> t ()
forall a b c. a -> b -> c -> a
!!)

-- | Run pipeline and get result
pipeline :: Pointable t => Pipeline i o t () () -> t ()
pipeline :: Pipeline i o t () () -> t ()
pipeline Pipeline i o t () ()
p = Pipe i o () t () -> Producer i t () -> Consumer o t () -> t ()
forall i o k (r :: k) (t :: k -> *) k (a :: k).
Pipe i o r t a -> Producer i t r -> Consumer o t r -> t r
pipe (Pipe i o () t () -> Producer i t () -> Consumer o t () -> t ())
-> Pipe i o () t () -> Producer i t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *). Category m => m ~~> m
/ Pipeline i o t () () -> (((->) ::|:. ()) :. Pipe i o () t) := ()
forall (t :: * -> *) a. Interpreted t => t a -> Primary t a
run Pipeline i o t () ()
p ((Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ()
forall k k i o (r :: k) (t :: k -> *) (a :: k).
(Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t a
Pipe ((Producer i t () -> Consumer o t () -> t ()) -> Pipe i o () t ())
-> (() -> Producer i t () -> Consumer o t () -> t ())
-> ()
-> Pipe i o () t ()
forall (m :: * -> * -> *) b c a.
Category m =>
m b c -> m a b -> m a c
. t () -> Producer i t () -> Consumer o t () -> t ()
forall a b c. a -> b -> c -> a
(!!) (t () -> Producer i t () -> Consumer o t () -> t ())
-> (() -> t ()) -> () -> Producer i t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *) b c a.
Category m =>
m b c -> m a b -> m a c
. () -> t ()
forall (t :: * -> *) a. Pointable t => a :=> t
point) (Producer i t () -> Consumer o t () -> t ())
-> Producer i t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *). Category m => m ~~> m
/ Producer i t ()
forall i (t :: * -> *). Producer i t ()
i (Consumer o t () -> t ()) -> Consumer o t () -> t ()
forall (m :: * -> * -> *). Category m => m ~~> m
/ Consumer o t ()
forall o (t :: * -> *). Consumer o t ()
o where

	i :: Producer i t ()
	i :: Producer i t ()
i = (Consumer i t () -> t ()) -> Producer i t ()
forall k i (t :: k -> *) (r :: k).
(Consumer i t r -> t r) -> Producer i t r
Producer ((Consumer i t () -> t ()) -> Producer i t ())
-> (Consumer i t () -> t ()) -> Producer i t ()
forall (m :: * -> * -> *). Category m => m ~~> m
$ \Consumer i t ()
o' -> Producer i t () -> Consumer i t () -> t ()
forall i k (t :: k -> *) (r :: k).
Producer i t r -> Consumer i t r -> t r
produce Producer i t ()
forall i (t :: * -> *). Producer i t ()
i Consumer i t ()
o'

	o :: Consumer o t ()
	o :: Consumer o t ()
o = (o -> Producer o t () -> t ()) -> Consumer o t ()
forall k o (t :: k -> *) (r :: k).
(o -> Producer o t r -> t r) -> Consumer o t r
Consumer ((o -> Producer o t () -> t ()) -> Consumer o t ())
-> (o -> Producer o t () -> t ()) -> Consumer o t ()
forall (m :: * -> * -> *). Category m => m ~~> m
$ \o
v Producer o t ()
i' -> Consumer o t () -> o -> Producer o t () -> t ()
forall o k (t :: k -> *) (r :: k).
Consumer o t r -> o -> Producer o t r -> t r
consume Consumer o t ()
forall o (t :: * -> *). Consumer o t ()
o o
v Producer o t ()
i'