rhine-1.6: src/FRP/Rhine/Clock/Unschedule.hs
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
-- | A clock that removes the 'ScheduleT' transformer from the stack by interpreting its actions in a monad
module FRP.Rhine.Clock.Unschedule where
-- base
import Control.Arrow
import Control.Concurrent qualified as Concurrent (yield)
import Control.Monad.IO.Class
-- monad-schedule
import Control.Monad.Schedule.Trans
-- automaton
import Data.Automaton (hoistS)
-- time-domain
import Data.TimeDomain (Diff, TimeDomain)
-- rhine
import FRP.Rhine.Clock
{- | If @cl@ is a 'Clock' in 'ScheduleT diff m', apply 'UnscheduleClock'
to get a clock in 'm'.
-}
data UnscheduleClock m cl = UnscheduleClock
{ scheduleClock :: cl
, scheduleWait :: Diff (Time cl) -> m ()
}
{- | Remove a 'ScheduleT' layer from the monad transformer stack of the clock.
The 'yield' action is interpreted as thread yielding in 'IO'.
-}
unyieldClock :: cl -> UnscheduleClock IO cl
unyieldClock cl = UnscheduleClock cl $ const $ liftIO Concurrent.yield
instance (TimeDomain (Time cl), Clock (ScheduleT (Diff (Time cl)) m) cl, Monad m) => Clock m (UnscheduleClock m cl) where
type Tag (UnscheduleClock _ cl) = Tag cl
type Time (UnscheduleClock _ cl) = Time cl
initClock UnscheduleClock {scheduleClock, scheduleWait} = run $ first (hoistS run) <$> initClock scheduleClock
where
run :: ScheduleT (Diff (Time cl)) m a -> m a
run = runScheduleT scheduleWait
{-# INLINE initClock #-}