{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module FRP.Rhine.Clock where
import Control.Monad.Trans.Class (lift, MonadTrans)
import Data.MonadicStreamFunction
import FRP.Rhine.TimeDomain
class TimeDomain (TimeDomainOf cl) => Clock m cl where
type TimeDomainOf cl
type Tag cl
startClock
:: cl
-> m (MSF m () (TimeDomainOf cl, Tag cl), TimeDomainOf cl)
data TimeInfo cl = TimeInfo
{
sinceTick :: Diff (TimeDomainOf cl)
, sinceStart :: Diff (TimeDomainOf cl)
, absolute :: TimeDomainOf cl
, tag :: Tag cl
}
retag
:: (TimeDomainOf cl1 ~ TimeDomainOf cl2)
=> (Tag cl1 -> Tag cl2)
-> TimeInfo cl1 -> TimeInfo cl2
retag f TimeInfo {..} = TimeInfo { tag = f tag, .. }
genTimeInfo
:: (Monad m, Clock m cl)
=> cl -> TimeDomainOf cl
-> MSF m (TimeDomainOf cl, Tag cl) (TimeInfo cl)
genTimeInfo _ initialTime = proc (absolute, tag) -> do
lastTime <- iPre initialTime -< absolute
returnA -< TimeInfo
{ sinceTick = absolute `diffTime` lastTime
, sinceStart = absolute `diffTime` initialTime
, ..
}
data RescaledClock cl td = RescaledClock
{ unscaledClock :: cl
, rescale :: TimeDomainOf cl -> td
}
instance (Monad m, TimeDomain td, Clock m cl)
=> Clock m (RescaledClock cl td) where
type TimeDomainOf (RescaledClock cl td) = td
type Tag (RescaledClock cl td) = Tag cl
startClock (RescaledClock cl f) = do
(runningClock, initTime) <- startClock cl
return
( runningClock >>> first (arr f)
, f initTime
)
data RescaledClockS m cl td tag = RescaledClockS
{ unscaledClockS :: cl
, rescaleS :: TimeDomainOf cl
-> m (MSF m (TimeDomainOf cl, Tag cl) (td, tag), td)
}
instance (Monad m, TimeDomain td, Clock m cl)
=> Clock m (RescaledClockS m cl td tag) where
type TimeDomainOf (RescaledClockS m cl td tag) = td
type Tag (RescaledClockS m cl td tag) = tag
startClock RescaledClockS {..} = do
(runningClock, initTime) <- startClock unscaledClockS
(rescaling, rescaledInitTime) <- rescaleS initTime
return
( runningClock >>> rescaling
, rescaledInitTime
)
data HoistClock m1 m2 cl = HoistClock
{ hoistedClock :: cl
, monadMorphism :: forall a . m1 a -> m2 a
}
instance (Monad m1, Monad m2, Clock m1 cl)
=> Clock m2 (HoistClock m1 m2 cl) where
type TimeDomainOf (HoistClock m1 m2 cl) = TimeDomainOf cl
type Tag (HoistClock m1 m2 cl) = Tag cl
startClock HoistClock {..} = do
(runningClock, initialTime) <- monadMorphism $ startClock hoistedClock
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 hoistedClock = HoistClock
{ monadMorphism = lift
, ..
}