-- |Combinators for looping with a sleep interval, Internal
module Polysemy.Time.Loop where

import Polysemy.Time.Data.TimeUnit (TimeUnit)
import qualified Polysemy.Time.Effect.Time as Time
import Polysemy.Time.Effect.Time (Time)

-- |Repeatedly run the @action@, sleeping for @interval@ between executions.
-- Stops when @action@ returns @Just a@, returning the contained @a@.
untilJust ::
   t d u r a .
  Member (Time t d) r =>
  TimeUnit u =>
  u ->
  Sem r (Maybe a) ->
  Sem r a
untilJust :: forall t d u (r :: EffectRow) a.
(Member (Time t d) r, TimeUnit u) =>
u -> Sem r (Maybe a) -> Sem r a
untilJust u
interval Sem r (Maybe a)
action =
  Sem r a
spin
  where
    spin :: Sem r a
spin =
      Sem r (Maybe a)
action forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Just a
a -> forall (f :: * -> *) a. Applicative f => a -> f a
pure a
a
        Maybe a
Nothing -> forall t d u (r :: EffectRow).
(TimeUnit u, Member (Time t d) r) =>
u -> Sem r ()
Time.sleep @t @d u
interval forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Sem r a
spin

-- |Repeatedly run the @action@, sleeping for @interval@ between executions.
-- Stops when @action@ returns @False@.
while ::
   t d u r .
  Member (Time t d) r =>
  TimeUnit u =>
  u ->
  Sem r Bool ->
  Sem r ()
while :: forall t d u (r :: EffectRow).
(Member (Time t d) r, TimeUnit u) =>
u -> Sem r Bool -> Sem r ()
while u
interval Sem r Bool
action =
  Sem r ()
spin
  where
    spin :: Sem r ()
spin =
      forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM Sem r Bool
action (forall t d u (r :: EffectRow).
(TimeUnit u, Member (Time t d) r) =>
u -> Sem r ()
Time.sleep @t @d u
interval forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> Sem r ()
spin)

-- |Repeatedly run the @action@, sleeping for @interval@ between executions.
-- The result of @action@ is passed back to it for the next run, starting with @initial@.
loop ::
   t d u a r .
  Member (Time t d) r =>
  TimeUnit u =>
  u ->
  a ->
  (a -> Sem r a) ->
  Sem r ()
loop :: forall t d u a (r :: EffectRow).
(Member (Time t d) r, TimeUnit u) =>
u -> a -> (a -> Sem r a) -> Sem r ()
loop u
interval a
initial a -> Sem r a
action =
  forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (a -> Sem r Any
spin a
initial)
  where
    spin :: a -> Sem r Any
spin a
a = do
      a
new <- a -> Sem r a
action a
a
      forall t d u (r :: EffectRow).
(TimeUnit u, Member (Time t d) r) =>
u -> Sem r ()
Time.sleep @t @d u
interval
      a -> Sem r Any
spin a
new

-- |Repeatedly run the @action@, sleeping for @interval@ between executions.
loop_ ::
   t d u r .
  Member (Time t d) r =>
  TimeUnit u =>
  u ->
  Sem r () ->
  Sem r ()
loop_ :: forall t d u (r :: EffectRow).
(Member (Time t d) r, TimeUnit u) =>
u -> Sem r () -> Sem r ()
loop_ u
interval Sem r ()
action =
  forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (Sem r ()
action forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> forall t d u (r :: EffectRow).
(TimeUnit u, Member (Time t d) r) =>
u -> Sem r ()
Time.sleep @t @d u
interval)