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

import Pandora.Pattern.Category (($))
import Pandora.Pattern.Functor.Covariant (Covariant ((<$>)))
import Pandora.Pattern.Functor.Contravariant (Contravariant ((>$<)))
import Pandora.Pattern.Functor.Pointable (Pointable (point))
import Pandora.Pattern.Functor.Bindable (Bindable ((>>=)))
import Pandora.Paradigm.Primary.Transformer.Continuation (Continuation (Continuation, continue))

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

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 }

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 }

instance Covariant (Pipe i o r t) where
	a -> b
_ <$> :: (a -> b) -> Pipe i o r t a -> Pipe i o r t b
<$> Pipe Producer i t r -> Consumer o t r -> t r
p = (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r t b
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
p

instance Contravariant (Pipe i o r t) where
	a -> b
_ >$< :: (a -> b) -> Pipe i o r t b -> Pipe i o r t a
>$< Pipe Producer i t r -> Consumer o t r -> t r
p = (Producer i t r -> Consumer o t r -> t r) -> Pipe i o r 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 r -> Consumer o t r -> t r
p

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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ () -> 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \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 (i -> Pipe i o r t a
next i
v) Producer i t r
ik 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer i t r
i Consumer o t r
o -> Producer i t r -> Consumer i t r -> t r
forall i k (t :: k -> *) (r :: k).
Producer i t r -> Consumer i t r -> t r
produce Producer i t r
i ((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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \() -> 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer i t r
i Consumer o t r
o -> Consumer o t r -> o -> Producer o t r -> t r
forall o k (t :: k -> *) (r :: k).
Consumer o t r -> o -> Producer o t r -> t r
consume Consumer o t r
o o
v ((() -> 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 (((((->) ::|:. ()) :. Pipe i o () t) := ())
 -> Pipeline i o t () ())
-> ((((->) ::|:. ()) :. Pipe i o () t) := ())
-> Pipeline i o t () ()
forall (m :: * -> * -> *) a b. Category m => m a b -> m a b
$ \() -> 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer i t ()
_ Consumer o t ()
_ -> () |-> t
forall (t :: * -> *) a. Pointable t => a |-> t
point ()

-- | 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \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 a o t . Pointable t => Pipeline i e t () () -> Pipeline e o t () () -> Pipeline i o t a ()
Pipeline i e t () ()
p =*= :: Pipeline i e t () () -> Pipeline e o t () () -> Pipeline i o t a ()
=*= Pipeline e o t () ()
q = ((((->) ::|:. a) :. Pipe i o () t) := ()) -> Pipeline i o t a ()
forall k (r :: k) (t :: k -> *) a.
((((->) ::|:. a) :. t) := r) -> Continuation r t a
Continuation (((((->) ::|:. a) :. Pipe i o () t) := ()) -> Pipeline i o t a ())
-> ((((->) ::|:. a) :. Pipe i o () t) := ()) -> Pipeline i o t a ()
forall (m :: * -> * -> *) a b. Category m => m a b -> m a b
$ \a -> 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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer i t ()
i Consumer o t ()
o -> 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 (Pipeline e o t () () -> (((->) ::|:. ()) :. Pipe e o () t) := ()
forall k (r :: k) (t :: k -> *) a.
Continuation r t a -> (((->) ::|:. a) :. t) := r
continue Pipeline e o t () ()
q () -> Pipe e o () t ()
forall b c d. b -> Pipe c d () t ()
end) ((() -> 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 k (r :: k) (t :: k -> *) a.
Continuation r t a -> (((->) ::|:. a) :. t) := r
continue Pipeline i e t () ()
p () -> Pipe i e () t ()
forall b c d. b -> Pipe c d () t ()
end) Producer i t ()
i) Consumer o t ()
o 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 ((Producer c t () -> Consumer d t () -> t ()) -> Pipe c d () t ())
-> (Producer c t () -> Consumer d t () -> t ()) -> Pipe c d () t ()
forall (m :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer c t ()
_ Consumer d t ()
_ -> () |-> t
forall (t :: * -> *) a. Pointable t => a |-> t
point ()

-- | Run pipeline and get result
pipeline :: Pointable t => Pipeline i o t r r -> t r
pipeline :: Pipeline i o t r r -> t r
pipeline Pipeline i o t r r
p = Pipe i o r t r -> 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 (Pipeline i o t r r -> (((->) ::|:. r) :. Pipe i o r t) := r
forall k (r :: k) (t :: k -> *) a.
Continuation r t a -> (((->) ::|:. a) :. t) := r
continue Pipeline i o t r r
p (\r
r -> (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 :: * -> * -> *) a b. Category m => m a b -> m a b
$ \Producer i t r
_ Consumer o t r
_ -> r |-> t
forall (t :: * -> *) a. Pointable t => a |-> t
point r
r)) Producer i t r
forall k i (t :: k -> *) (r :: k). Producer i t r
i Consumer o t r
forall k o (t :: k -> *) (r :: k). Consumer o t r
o where

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

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