packages feed

atelier-core-1.0.0.0: src/Atelier/Effects/Delay.hs

module Atelier.Effects.Delay
    ( Delay
    , wait
    , every
    , runIO
    , runNoOp
    )
where

import Data.Time.Units (TimeUnit, toMicroseconds)
import Effectful (Effect)
import Effectful.Concurrent (Concurrent, threadDelay)
import Effectful.Dispatch.Dynamic (interpret_)
import Effectful.TH (makeEffect)


-- | Effect for suspending execution for a given duration.
data Delay :: Effect where
    -- | Halt the thread and wait for the passed duration before continuing.
    Wait :: (TimeUnit t) => t -> Delay m ()


makeEffect ''Delay


-- | Runs an action repeatedly, waiting the given duration in between each
-- execution, starting immediately.
every :: (Delay :> es, TimeUnit t) => t -> Eff es () -> Eff es Void
every delay action = forever do
    action
    wait delay


-- | Interpret 'Delay' using real thread delays.
runIO :: (Concurrent :> es) => Eff (Delay : es) a -> Eff es a
runIO = interpret_ \(Wait delay) ->
    threadDelay $ fromIntegral (toMicroseconds delay)


-- | Delay interpreter that makes every 'wait' return immediately.
runNoOp :: Eff (Delay : es) a -> Eff es a
runNoOp = interpret_ \(Wait _) -> pure ()