packages feed

drama-0.3.0.0: src/Drama/Loop.hs

{-# LANGUAGE LambdaCase #-}

-- |
-- Module:     Drama.Loop
-- Stability:  experimental
-- License:    BSD-3-Clause
-- Copyright:  © 2021 Evan Relf
-- Maintainer: evan@evanrelf.com

module Drama.Loop
  ( loop
  , continue
  , stop

    -- * Re-exports
  , forever
  )
where

import Control.Monad (forever)


-- | Loop indefinitely with state. Use `Control.Monad.forever` for stateless
-- infinite loops.
--
-- ===== __ Example __
--
-- > counter :: Process NoMsg ()
-- > counter = loop (10 :: Int) \count -> do
-- >   liftIO $ print count
-- >   if count > 0
-- >     then continue (count - 1)
-- >     else exit ()
--
-- @since 0.3.0.0
loop
  :: Monad m
  => s
  -- ^ Initial state
  -> (s -> m (Either s a))
  -- ^ Action to perform, returning either a new state to continue looping, or
  -- a final value to stop looping.
  -> m a
loop s0 k =
  k s0 >>= \case
    Left s -> loop s k
    Right x -> pure x


-- | Continue looping with some new state.
--
-- prop> continue s = pure (Left s)
--
-- @since 0.3.0.0
continue :: Monad m => s -> m (Either s a)
continue s = pure (Left s)


-- | Stop looping and return with a final value.
--
-- prop> exit x = pure (Right x)
--
-- @since 0.3.0.0
stop :: Monad m => a -> m (Either s a)
stop x = pure (Right x)