{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
module FRP.Rhine.Clock
( module FRP.Rhine.Clock
, module X
)
where
import qualified Control.Category as Category
import Control.Monad.IO.Class (liftIO, MonadIO)
import Control.Monad.Trans.Class (lift, MonadTrans)
import Data.MonadicStreamFunction as X hiding ((>>>^), (^>>>))
import FRP.Rhine.TimeDomain as X
type RunningClock m time tag = MSF m () (time, tag)
type RunningClockInit m time tag = m (RunningClock m time tag, time)
class TimeDomain (Time cl) => Clock m cl where
type Time cl
type Tag cl
initClock
:: cl
-> RunningClockInit m (Time cl) (Tag cl)
data TimeInfo cl = TimeInfo
{
sinceLast :: Diff (Time cl)
, sinceInit :: Diff (Time cl)
, absolute :: Time cl
, tag :: Tag cl
}
retag
:: (Time cl1 ~ Time cl2)
=> (Tag cl1 -> Tag cl2)
-> TimeInfo cl1 -> TimeInfo cl2
retag f TimeInfo {..} = TimeInfo { tag = f tag, .. }
genTimeInfo
:: (Monad m, Clock m cl)
=> cl -> Time cl
-> MSF m (Time cl, Tag cl) (TimeInfo cl)
genTimeInfo _ initialTime = proc (absolute, tag) -> do
lastTime <- iPre initialTime -< absolute
returnA -< TimeInfo
{ sinceLast = absolute `diffTime` lastTime
, sinceInit = absolute `diffTime` initialTime
, ..
}
type Rescaling cl time = Time cl -> time
type RescalingM m cl time = Time cl -> m time
type RescalingS m cl time tag = MSF m (Time cl, Tag cl) (time, tag)
type RescalingSInit m cl time tag = Time cl -> m (RescalingS m cl time tag, time)
rescaleMToSInit
:: Monad m
=> (time1 -> m time2) -> time1 -> m (MSF m (time1, tag) (time2, tag), time2)
rescaleMToSInit rescaling time1 = (arrM rescaling *** Category.id, ) <$> rescaling time1
data RescaledClock cl time = RescaledClock
{ unscaledClock :: cl
, rescale :: Rescaling cl time
}
instance (Monad m, TimeDomain time, Clock m cl)
=> Clock m (RescaledClock cl time) where
type Time (RescaledClock cl time) = time
type Tag (RescaledClock cl time) = Tag cl
initClock (RescaledClock cl f) = do
(runningClock, initTime) <- initClock cl
return
( runningClock >>> first (arr f)
, f initTime
)
data RescaledClockM m cl time = RescaledClockM
{ unscaledClockM :: cl
, rescaleM :: RescalingM m cl time
}
instance (Monad m, TimeDomain time, Clock m cl)
=> Clock m (RescaledClockM m cl time) where
type Time (RescaledClockM m cl time) = time
type Tag (RescaledClockM m cl time) = Tag cl
initClock RescaledClockM {..} = do
(runningClock, initTime) <- initClock unscaledClockM
rescaledInitTime <- rescaleM initTime
return
( runningClock >>> first (arrM rescaleM)
, rescaledInitTime
)
rescaledClockToM :: Monad m => RescaledClock cl time -> RescaledClockM m cl time
rescaledClockToM RescaledClock {..} = RescaledClockM
{ unscaledClockM = unscaledClock
, rescaleM = return . rescale
}
data RescaledClockS m cl time tag = RescaledClockS
{ unscaledClockS :: cl
, rescaleS :: RescalingSInit m cl time tag
}
instance (Monad m, TimeDomain time, Clock m cl)
=> Clock m (RescaledClockS m cl time tag) where
type Time (RescaledClockS m cl time tag) = time
type Tag (RescaledClockS m cl time tag) = tag
initClock RescaledClockS {..} = do
(runningClock, initTime) <- initClock unscaledClockS
(rescaling, rescaledInitTime) <- rescaleS initTime
return
( runningClock >>> rescaling
, rescaledInitTime
)
rescaledClockMToS
:: Monad m
=> RescaledClockM m cl time -> RescaledClockS m cl time (Tag cl)
rescaledClockMToS RescaledClockM {..} = RescaledClockS
{ unscaledClockS = unscaledClockM
, rescaleS = rescaleMToSInit rescaleM
}
rescaledClockToS
:: Monad m
=> RescaledClock cl time -> RescaledClockS m cl time (Tag cl)
rescaledClockToS = rescaledClockMToS . rescaledClockToM
data HoistClock m1 m2 cl = HoistClock
{ unhoistedClock :: cl
, monadMorphism :: forall a . m1 a -> m2 a
}
instance (Monad m1, Monad m2, Clock m1 cl)
=> Clock m2 (HoistClock m1 m2 cl) where
type Time (HoistClock m1 m2 cl) = Time cl
type Tag (HoistClock m1 m2 cl) = Tag cl
initClock HoistClock {..} = do
(runningClock, initialTime) <- monadMorphism $ initClock unhoistedClock
let hoistMSF = liftMSFPurer
return
( hoistMSF monadMorphism runningClock
, initialTime
)
type LiftClock m t cl = HoistClock m (t m) cl
liftClock :: (Monad m, MonadTrans t) => cl -> LiftClock m t cl
liftClock unhoistedClock = HoistClock
{ monadMorphism = lift
, ..
}
type IOClock m cl = HoistClock IO m cl
ioClock :: MonadIO m => cl -> IOClock m cl
ioClock unhoistedClock = HoistClock
{ monadMorphism = liftIO
, ..
}