module Control.Effect.Coroutine
  ( Coroutine(..)
  , yield
  , Status(..)
  , runCoroutine
  ) where

import Control.Effect.Base

data Coroutine a b :: Effect where
  Yield :: a -> Coroutine a b m b

yield :: Coroutine a b :< effs => a -> Eff effs b
yield :: a -> Eff effs b
yield = Coroutine a b (Eff effs) b -> Eff effs b
forall (eff :: Effect) a (effs :: [Effect]).
(eff :< effs) =>
eff (Eff effs) a -> Eff effs a
send (Coroutine a b (Eff effs) b -> Eff effs b)
-> (a -> Coroutine a b (Eff effs) b) -> a -> Eff effs b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Coroutine a b (Eff effs) b
forall a b (m :: * -> *). a -> Coroutine a b m b
Yield

data Status effs a b c
  = Done c
  | Yielded a !(b -> Eff (Coroutine a b ': effs) c)

runCoroutine :: Eff (Coroutine a b ': effs) c -> Eff effs (Status effs a b c)
runCoroutine :: Eff (Coroutine a b : effs) c -> Eff effs (Status effs a b c)
runCoroutine = (c -> Eff effs (Status effs a b c))
-> (forall (effs' :: [Effect]) b.
    (Coroutine a b :< effs') =>
    Coroutine a b (Eff effs') b
    -> Handle (Coroutine a b) effs c (Status effs a b c) effs' b)
-> Eff (Coroutine a b : effs) c
-> Eff effs (Status effs a b c)
forall (eff :: Effect) a r (effs :: [Effect]).
(a -> Eff effs r)
-> (forall (effs' :: [Effect]) b.
    (eff :< effs') =>
    eff (Eff effs') b -> Handle eff effs a r effs' b)
-> Eff (eff : effs) a
-> Eff effs r
handle (Status effs a b c -> Eff effs (Status effs a b c)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Status effs a b c -> Eff effs (Status effs a b c))
-> (c -> Status effs a b c) -> c -> Eff effs (Status effs a b c)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. c -> Status effs a b c
forall (effs :: [Effect]) a b c. c -> Status effs a b c
Done) \case
  Yield a -> ((b -> Eff (Coroutine a b : effs) c)
 -> Eff effs (Status effs a b c))
-> Handle (Coroutine a b) effs c (Status effs a b c) effs' b
forall a (eff :: Effect) (effs :: [Effect]) i r
       (effs' :: [Effect]).
((a -> Eff (eff : effs) i) -> Eff effs r)
-> Handle eff effs i r effs' a
control0 \b -> Eff (Coroutine a b : effs) c
k -> Status effs a b c -> Eff effs (Status effs a b c)
forall (f :: * -> *) a. Applicative f => a -> f a
pure (Status effs a b c -> Eff effs (Status effs a b c))
-> Status effs a b c -> Eff effs (Status effs a b c)
forall a b. (a -> b) -> a -> b
$! a -> (b -> Eff (Coroutine a b : effs) c) -> Status effs a b c
forall (effs :: [Effect]) a b c.
a -> (b -> Eff (Coroutine a b : effs) c) -> Status effs a b c
Yielded a
a b -> Eff (Coroutine a b : effs) c
k