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

import Pandora.Pattern.Semigroupoid ((.))
import Pandora.Pattern.Category (($), (#))
import Pandora.Pattern.Functor.Bindable (Bindable ((=<<)))
import Pandora.Pattern.Functor.Monoidal (Monoidal)
import Pandora.Paradigm.Primary.Algebraic.Exponential ((!.), (!..))
import Pandora.Paradigm.Primary.Algebraic.Product ((:*:))
import Pandora.Paradigm.Primary.Algebraic (point)
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 :: * -> * -> *) a b. Category m => 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 (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 (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 (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 (m a b) (m a b)
# 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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# Producer i t r
ik (Consumer o t r -> t r) -> Consumer o t r -> t r
forall (m :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# 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 (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 (m a b) (m a b)
$ \(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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# (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 (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 (m a b) (m a b)
$ \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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# (() -> 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 :: Monoidal (->) (->) (:*:) (:*:) 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.
Monoidal (->) (->) (:*:) (:*:) t =>
a -> t a
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 :: * -> * -> *) a b. Category m => 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 (m a b) (m a b)
$ \Producer i t a
i Consumer o t a
o -> (\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) (a -> t a) -> t a -> t a
forall (source :: * -> * -> *) (t :: * -> *) a b.
Bindable source t =>
source a (t b) -> source (t a) (t b)
=<< t a
action

-- | Compose two pipelines into one
(=*=) :: forall i e o t . Monoidal (->) (->) (:*:) (:*:) 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 :: * -> * -> *) a b. Category m => 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 (m a b) (m a b)
$ \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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# 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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# (() -> 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.
Monoidal (->) (->) (:*:) (:*:) t =>
a -> t a
point () t () -> Producer c t () -> Consumer d t () -> t ()
forall a b c. a -> b -> c -> a
!..)

-- | Run pipeline and get result
pipeline :: Monoidal (->) (->) (:*:) (:*:) 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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# 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.
Semigroupoid 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.
Semigroupoid m =>
m b c -> m a b -> m a c
. () -> t ()
forall (t :: * -> *) a.
Monoidal (->) (->) (:*:) (:*:) t =>
a -> t a
point) (Producer i t () -> Consumer o t () -> t ())
-> Producer i t () -> Consumer o t () -> t ()
forall (m :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# Producer i t ()
forall i (t :: * -> *). Producer i t ()
i (Consumer o t () -> t ()) -> Consumer o t () -> t ()
forall (m :: * -> * -> *) a b. Category m => m (m a b) (m a b)
# 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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
$ \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 :: * -> * -> *) a b. Category m => m (m a b) (m a b)
$ \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'