module Control.Effect.Coroutine (
EffectCoroutine, Coroutine, runCoroutine, suspend,
Iterator (..), evalIterator
) where
import Control.Monad.Effect
data Coroutine i o a = Coroutine (o -> a) i
type instance Is Coroutine f = IsCoroutine f
type family IsCoroutine f where
IsCoroutine (Coroutine i o) = 'True
IsCoroutine f = 'False
class MemberEffect Coroutine (Coroutine i o) l => EffectCoroutine i o l
instance MemberEffect Coroutine (Coroutine i o) l => EffectCoroutine i o l
suspend :: EffectCoroutine i o l => i -> Effect l o
suspend = send . Coroutine id
runCoroutine :: Effect (Coroutine i o ':+ l) a -> Effect l (Iterator i o l a)
runCoroutine = eliminate (return . Done) (\(Coroutine f x) k -> return (Next (k . f) x))
data Iterator i o l a
= Done a
| Next (o -> Effect l (Iterator i o l a)) i
evalIterator :: Iterator i o l a -> [o] -> Effect l (Iterator i o l a, [i])
evalIterator (Next f v) (x:xs) = do
i <- f x
(r, vs) <- evalIterator i xs
return (r, v:vs)
evalIterator i _ = return (i, [])