{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module FRP.Rhine.Schedule where
import Data.Semigroup
import Control.Monad.Trans.Reader
import Data.MonadicStreamFunction
import FRP.Rhine.Clock
import FRP.Rhine.Schedule.Util
data Schedule m cl1 cl2
= (Time cl1 ~ Time cl2)
=> Schedule
{ initSchedule
:: cl1 -> cl2
-> RunningClockInit m (Time cl1) (Either (Tag cl1) (Tag cl2))
}
hoistSchedule
:: (Monad m1, Monad m2)
=> (forall a . m1 a -> m2 a)
-> Schedule m1 cl1 cl2
-> Schedule m2 cl1 cl2
hoistSchedule hoist Schedule {..} = Schedule initSchedule'
where
initSchedule' cl1 cl2 = hoist
$ first (hoistMSF hoist) <$> initSchedule cl1 cl2
hoistMSF = liftMSFPurer
flipSchedule
:: Monad m
=> Schedule m cl1 cl2
-> Schedule m cl2 cl1
flipSchedule Schedule {..} = Schedule initSchedule_
where
initSchedule_ cl2 cl1 = first (arr (second swapEither) <<<) <$> initSchedule cl1 cl2
rescaledSchedule
:: Monad m
=> Schedule m cl1 cl2
-> Schedule m (RescaledClock cl1 time) (RescaledClock cl2 time)
rescaledSchedule schedule = Schedule $ initSchedule'
where
initSchedule' cl1 cl2 = initSchedule (rescaledScheduleS schedule) (rescaledClockToS cl1) (rescaledClockToS cl2)
rescaledScheduleS
:: Monad m
=> Schedule m cl1 cl2
-> Schedule m (RescaledClockS m cl1 time tag1) (RescaledClockS m cl2 time tag2)
rescaledScheduleS Schedule {..} = Schedule initSchedule'
where
initSchedule' (RescaledClockS cl1 rescaleS1) (RescaledClockS cl2 rescaleS2) = do
(runningSchedule, initTime ) <- initSchedule cl1 cl2
(rescaling1 , initTime') <- rescaleS1 initTime
(rescaling2 , _ ) <- rescaleS2 initTime
let runningSchedule'
= runningSchedule >>> proc (time, tag12) -> case tag12 of
Left tag1 -> do
(time', tag1') <- rescaling1 -< (time, tag1)
returnA -< (time', Left tag1')
Right tag2 -> do
(time', tag2') <- rescaling2 -< (time, tag2)
returnA -< (time', Right tag2')
return (runningSchedule', initTime')
readerSchedule
:: ( Monad m
, Clock (ReaderT r m) cl1, Clock (ReaderT r m) cl2
, Time cl1 ~ Time cl2
)
=> Schedule m
(HoistClock (ReaderT r m) m cl1) (HoistClock (ReaderT r m) m cl2)
-> Schedule (ReaderT r m) cl1 cl2
readerSchedule Schedule {..}
= Schedule $ \cl1 cl2 -> ReaderT $ \r -> first liftMSFTrans
<$> initSchedule
(HoistClock cl1 $ flip runReaderT r)
(HoistClock cl2 $ flip runReaderT r)
data SequentialClock m cl1 cl2
= Time cl1 ~ Time cl2
=> SequentialClock
{ sequentialCl1 :: cl1
, sequentialCl2 :: cl2
, sequentialSchedule :: Schedule m cl1 cl2
}
type SeqClock m cl1 cl2 = SequentialClock m cl1 cl2
instance (Monad m, Clock m cl1, Clock m cl2)
=> Clock m (SequentialClock m cl1 cl2) where
type Time (SequentialClock m cl1 cl2) = Time cl1
type Tag (SequentialClock m cl1 cl2) = Either (Tag cl1) (Tag cl2)
initClock SequentialClock {..}
= initSchedule sequentialSchedule sequentialCl1 sequentialCl2
schedSeq1 :: (Monad m, Semigroup cl1) => Schedule m cl1 (SequentialClock m cl1 cl2)
schedSeq1 = Schedule $ \cl1 SequentialClock { sequentialSchedule = Schedule {..}, .. } -> do
(runningClock, initTime) <- initSchedule (cl1 <> sequentialCl1) sequentialCl2
return (duplicateSubtick runningClock, initTime)
schedSeq2 :: (Monad m, Semigroup cl2, Time cl1 ~ Time cl2) => Schedule m (SequentialClock m cl1 cl2) cl2
schedSeq2 = Schedule $ \SequentialClock { sequentialSchedule = Schedule {..}, .. } cl2 -> do
(runningClock, initTime) <- initSchedule sequentialCl1 (sequentialCl2 <> cl2)
return (duplicateSubtick (runningClock >>> second (arr swapEither)) >>> second (arr remap), initTime)
where
remap (Left tag2) = Left $ Right tag2
remap (Right (Left tag2)) = Right tag2
remap (Right (Right tag1)) = Left $ Left tag1
data ParallelClock m cl1 cl2
= Time cl1 ~ Time cl2
=> ParallelClock
{ parallelCl1 :: cl1
, parallelCl2 :: cl2
, parallelSchedule :: Schedule m cl1 cl2
}
type ParClock m cl1 cl2 = ParallelClock m cl1 cl2
instance (Monad m, Clock m cl1, Clock m cl2)
=> Clock m (ParallelClock m cl1 cl2) where
type Time (ParallelClock m cl1 cl2) = Time cl1
type Tag (ParallelClock m cl1 cl2) = Either (Tag cl1) (Tag cl2)
initClock ParallelClock {..}
= initSchedule parallelSchedule parallelCl1 parallelCl2
schedPar1 :: (Monad m, Semigroup cl1) => Schedule m cl1 (ParallelClock m cl1 cl2)
schedPar1 = Schedule $ \cl1 ParallelClock { parallelSchedule = Schedule {..}, .. } -> do
(runningClock, initTime) <- initSchedule (cl1 <> parallelCl1) parallelCl2
return (duplicateSubtick runningClock, initTime)
schedPar1' :: (Monad m, Semigroup cl1) => Schedule m cl1 (ParallelClock m cl1 cl2)
schedPar1' = Schedule $ \cl1 ParallelClock { parallelSchedule = Schedule {..}, .. } -> do
(runningClock, initTime) <- initSchedule (parallelCl1 <> cl1) parallelCl2
return (duplicateSubtick runningClock >>> arr (second remap), initTime)
where
remap (Left tag1) = Right $ Left tag1
remap (Right (Left tag1)) = Left tag1
remap tag = tag
schedPar2 :: (Monad m, Semigroup cl2, Time cl1 ~ Time cl2) => Schedule m (ParallelClock m cl1 cl2) cl2
schedPar2 = Schedule $ \ParallelClock { parallelSchedule = Schedule {..}, .. } cl2 -> do
(runningClock, initTime) <- initSchedule parallelCl1 (parallelCl2 <> cl2)
return (duplicateSubtick (runningClock >>> second (arr swapEither)) >>> second (arr remap), initTime)
where
remap (Left tag2) = Left $ Right tag2
remap (Right (Left tag2)) = Right tag2
remap (Right (Right tag1)) = Left $ Left tag1
schedPar2' :: (Monad m, Semigroup cl2, Time cl1 ~ Time cl2) => Schedule m (ParallelClock m cl1 cl2) cl2
schedPar2' = Schedule $ \ParallelClock { parallelSchedule = Schedule {..}, .. } cl2 -> do
(runningClock, initTime) <- initSchedule parallelCl1 (parallelCl2 <> cl2)
return (duplicateSubtick (runningClock >>> second (arr swapEither)) >>> second (arr remap), initTime)
where
remap (Left tag2) = Right tag2
remap (Right (Left tag2)) = Left $ Right tag2
remap (Right (Right tag1)) = Left $ Left tag1
type family In cl where
In (SequentialClock m cl1 cl2) = In cl1
In (ParallelClock m cl1 cl2) = ParallelClock m (In cl1) (In cl2)
In cl = cl
type family Out cl where
Out (SequentialClock m cl1 cl2) = Out cl2
Out (ParallelClock m cl1 cl2) = ParallelClock m (Out cl1) (Out cl2)
Out cl = cl
data LastTime cl where
SequentialLastTime
:: LastTime cl1 -> LastTime cl2
-> LastTime (SequentialClock m cl1 cl2)
ParallelLastTime
:: LastTime cl1 -> LastTime cl2
-> LastTime (ParallelClock m cl1 cl2)
LeafLastTime :: Time cl -> LastTime cl
data ParClockInclusion clS cl where
ParClockInL
:: ParClockInclusion (ParallelClock m clL clR) cl
-> ParClockInclusion clL cl
ParClockInR
:: ParClockInclusion (ParallelClock m clL clR) cl
-> ParClockInclusion clR cl
ParClockRefl :: ParClockInclusion cl cl
parClockTagInclusion :: ParClockInclusion clS cl -> Tag clS -> Tag cl
parClockTagInclusion (ParClockInL parClockInL) tag = parClockTagInclusion parClockInL $ Left tag
parClockTagInclusion (ParClockInR parClockInR) tag = parClockTagInclusion parClockInR $ Right tag
parClockTagInclusion ParClockRefl tag = tag