packages feed

polysemy-time-0.5.1.0: lib/Polysemy/Time/Loop.hs

-- |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 interval action =
  spin
  where
    spin =
      action >>= \case
        Just a -> pure a
        Nothing -> Time.sleep @t @d interval *> 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 interval action =
  spin
  where
    spin =
      whenM action (Time.sleep @t @d interval *> 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 interval initial action =
  forever (spin initial)
  where
    spin a = do
      new <- action a
      Time.sleep @t @d interval
      spin 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_ interval action =
  forever (action *> Time.sleep @t @d interval)