module Polysemy.Time.Loop where

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

-- |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 :: u -> Sem r Bool -> Sem r ()
while u
interval Sem r Bool
action =
  Sem r ()
spin
  where
    spin :: Sem r ()
spin =
      Sem r Bool -> Sem r () -> Sem r ()
forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM Sem r Bool
action (u -> Sem r ()
forall t d (r :: [Effect]) u.
(MemberWithError (Time t d) r, TimeUnit u) =>
u -> Sem r ()
Time.sleep @t @d u
interval Sem r () -> Sem r () -> Sem r ()
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 :: u -> a -> (a -> Sem r a) -> Sem r ()
loop u
interval a
initial a -> Sem r a
action =
  Sem r Any -> Sem r ()
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
      u -> Sem r ()
forall t d (r :: [Effect]) u.
(MemberWithError (Time t d) r, TimeUnit u) =>
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_ :: u -> Sem r () -> Sem r ()
loop_ u
interval Sem r ()
action =
  Sem r () -> Sem r ()
forall (f :: * -> *) a b. Applicative f => f a -> f b
forever (Sem r ()
action Sem r () -> Sem r () -> Sem r ()
forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
*> u -> Sem r ()
forall t d (r :: [Effect]) u.
(MemberWithError (Time t d) r, TimeUnit u) =>
u -> Sem r ()
Time.sleep @t @d u
interval)