Skip to content

Commit

Permalink
Simplify initClock
Browse files Browse the repository at this point in the history
  • Loading branch information
turion committed Jul 18, 2024
1 parent dae1b37 commit 2de85f0
Show file tree
Hide file tree
Showing 25 changed files with 120 additions and 263 deletions.
4 changes: 2 additions & 2 deletions rhine-gloss/src/FRP/Rhine/Gloss/IO.hs
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ data GlossEventClockIO = GlossEventClockIO
instance (MonadIO m) => Clock (GlossConcT m) GlossEventClockIO where
type Time GlossEventClockIO = Float
type Tag GlossEventClockIO = Event
initClock _ = return (constM getEvent, 0)
initClock _ = constM getEvent
where
getEvent = do
GlossEnv {eventVar, timeRef} <- GlossConcT ask
Expand All @@ -148,7 +148,7 @@ data GlossSimClockIO = GlossSimClockIO
instance (MonadIO m) => Clock (GlossConcT m) GlossSimClockIO where
type Time GlossSimClockIO = Float
type Tag GlossSimClockIO = ()
initClock _ = return (constM getTime &&& arr (const ()), 0)
initClock _ = constM getTime &&& arr (const ())
where
getTime = GlossConcT $ do
GlossEnv {timeVar} <- ask
Expand Down
5 changes: 2 additions & 3 deletions rhine-gloss/src/FRP/Rhine/Gloss/Pure.hs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ import Control.Monad.Schedule.Class
import Control.Monad.Schedule.Yield

-- automaton
import Data.Automaton.Trans.Except (performOnFirstSample)
import qualified Data.Automaton.Trans.Reader as AutomatonReader
import qualified Data.Automaton.Trans.Writer as AutomatonWriter

Expand Down Expand Up @@ -82,7 +81,7 @@ instance Semigroup GlossClock where
instance Clock GlossM GlossClock where
type Time GlossClock = Float
type Tag GlossClock = Maybe Event
initClock _ = return (constM (GlossM $ yield >> lift ask) >>> (sumS *** Category.id), 0)
initClock _ = constM (GlossM $ yield >> lift ask) >>> (sumS *** Category.id)

instance GetClockProxy GlossClock

Expand Down Expand Up @@ -125,7 +124,7 @@ flowGloss GlossSettings {..} rhine =
play display backgroundColor stepsPerSecond (worldAutomaton, Blank) getPic handleEvent simStep
where
worldAutomaton :: WorldAutomaton
worldAutomaton = AutomatonWriter.runWriterS $ AutomatonReader.runReaderS $ hoistS (runYieldT . unGlossM) $ performOnFirstSample $ eraseClock rhine
worldAutomaton = AutomatonWriter.runWriterS $ AutomatonReader.runReaderS $ hoistS (runYieldT . unGlossM) $ eraseClock rhine
stepWith :: (Float, Maybe Event) -> (WorldAutomaton, Picture) -> (WorldAutomaton, Picture)
stepWith (diff, eventMaybe) (automaton, _) = let Result automaton' (picture, _) = runIdentity $ stepAutomaton automaton ((diff, eventMaybe), ()) in (automaton', picture)
getPic (_, pic) = pic
Expand Down
13 changes: 4 additions & 9 deletions rhine-terminal/src/FRP/Rhine/Terminal.hs
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,10 @@ instance (MonadInput m, MonadIO m) => Clock m TerminalEventClock where
type Time TerminalEventClock = UTCTime
type Tag TerminalEventClock = Either Interrupt Event

initClock TerminalEventClock = do
initialTime <- liftIO getCurrentTime
return
( constM $ do
event <- awaitEvent
time <- liftIO getCurrentTime
return (time, event)
, initialTime
)
initClock TerminalEventClock = constM $ do
event <- awaitEvent
time <- liftIO getCurrentTime
return (time, event)

instance GetClockProxy TerminalEventClock

Expand Down
60 changes: 12 additions & 48 deletions rhine/src/FRP/Rhine/Clock.hs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}

{- |
Expand Down Expand Up @@ -40,13 +39,6 @@ that cause the environment to wait until the specified time is reached.
-}
type RunningClock m time tag = Automaton m () (time, tag)

{- |
When initialising a clock, the initial time is measured
(typically by means of a side effect),
and a running clock is returned.
-}
type RunningClockInit m time tag = m (RunningClock m time tag, time)

{- |
Since we want to leverage Haskell's type system to annotate signal networks by their clocks,
each clock must be an own type, 'cl'.
Expand All @@ -69,7 +61,7 @@ class (TimeDomain (Time cl)) => Clock m cl where
-- | The clock value, containing e.g. settings or device parameters
cl ->
-- | The stream of time stamps, and the initial time
RunningClockInit m (Time cl) (Tag cl)
RunningClock m (Time cl) (Tag cl)

-- * Auxiliary definitions and utilities

Expand Down Expand Up @@ -112,21 +104,15 @@ type RescalingM m cl time = Time cl -> m time
-}
type RescalingS m cl time tag = Automaton m (Time cl, Tag cl) (time, tag)

{- | Like 'RescalingS', but allows for an initialisation
of the rescaling morphism, together with the initial time.
-}
type RescalingSInit m cl time tag = Time cl -> m (RescalingS m cl time tag, time)

{- | Convert an effectful morphism of time domains into a stateful one with initialisation.
Think of its type as @RescalingM m cl time -> RescalingSInit m cl time tag@,
{- | Convert an effectful morphism of time domains into a stateful one.
Think of its type as @'RescalingM' m cl time -> 'RescalingS' m cl time tag@,
although this type is ambiguous.
-}
rescaleMToSInit ::
rescaleMToS ::
(Monad m) =>
(time1 -> m time2) ->
time1 ->
m (Automaton m (time1, tag) (time2, tag), time2)
rescaleMToSInit rescaling time1 = (arrM rescaling *** Category.id,) <$> rescaling time1
Automaton m (time1, tag) (time2, tag)
rescaleMToS rescaling = arrM rescaling *** Category.id

-- ** Applying rescalings to clocks

Expand All @@ -142,12 +128,7 @@ instance
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
)
initClock (RescaledClock cl f) = initClock cl >>> first (arr f)

{- | Instead of a mere function as morphism of time domains,
we can transform one time domain into the other with an effectful morphism.
Expand All @@ -165,13 +146,7 @@ instance
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
)
initClock RescaledClockM {..} = initClock unscaledClockM >>> first (arrM rescaleM)

-- | A 'RescaledClock' is trivially a 'RescaledClockM'.
rescaledClockToM :: (Monad m) => RescaledClock cl time -> RescaledClockM m cl time
Expand All @@ -187,7 +162,7 @@ rescaledClockToM RescaledClock {..} =
data RescaledClockS m cl time tag = RescaledClockS
{ unscaledClockS :: cl
-- ^ The clock before the rescaling
, rescaleS :: RescalingSInit m cl time tag
, rescaleS :: RescalingS m cl time tag
-- ^ The rescaling stream function, and rescaled initial time,
-- depending on the initial time before rescaling
}
Expand All @@ -198,13 +173,7 @@ instance
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
)
initClock RescaledClockS {..} = initClock unscaledClockS >>> rescaleS

-- | A 'RescaledClockM' is trivially a 'RescaledClockS'.
rescaledClockMToS ::
Expand All @@ -214,7 +183,7 @@ rescaledClockMToS ::
rescaledClockMToS RescaledClockM {..} =
RescaledClockS
{ unscaledClockS = unscaledClockM
, rescaleS = rescaleMToSInit rescaleM
, rescaleS = rescaleMToS rescaleM
}

-- | A 'RescaledClock' is trivially a 'RescaledClockS'.
Expand All @@ -236,12 +205,7 @@ instance
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
return
( hoistS monadMorphism runningClock
, initialTime
)
initClock HoistClock {..} = hoistS monadMorphism $ initClock unhoistedClock

-- | Lift a clock type into a monad transformer.
type LiftClock m t cl = HoistClock m (t m) cl
Expand Down
37 changes: 12 additions & 25 deletions rhine/src/FRP/Rhine/Clock/Except.hs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import Control.Arrow
import Control.Exception
import Control.Exception qualified as Exception
import Control.Monad ((<=<))
import Data.Functor ((<&>))
import Data.Void

-- time
Expand Down Expand Up @@ -50,11 +49,7 @@ instance (Exception e, Clock IO cl, MonadIO eio, MonadError e eio) => Clock eio
type Time (ExceptClock cl e) = Time cl
type Tag (ExceptClock cl e) = Tag cl

initClock ExceptClock {getExceptClock} = do
ioerror $
Exception.try $
initClock getExceptClock
<&> first (hoistS (ioerror . Exception.try))
initClock ExceptClock {getExceptClock} = hoistS (ioerror . Exception.try) $ initClock getExceptClock
where
ioerror :: (MonadError e eio, MonadIO eio) => IO (Either e a) -> eio a
ioerror = liftEither <=< liftIO
Expand All @@ -76,17 +71,10 @@ data CatchClock cl1 e cl2 = CatchClock cl1 (e -> cl2)
instance (Time cl1 ~ Time cl2, Clock (ExceptT e m) cl1, Clock m cl2, Monad m) => Clock m (CatchClock cl1 e cl2) where
type Time (CatchClock cl1 e cl2) = Time cl1
type Tag (CatchClock cl1 e cl2) = Either (Tag cl2) (Tag cl1)
initClock (CatchClock cl1 handler) = do
tryToInit <- runExceptT $ first (>>> arr (second Right)) <$> initClock cl1
case tryToInit of
Right (runningClock, initTime) -> do
let catchingClock = safely $ do
e <- AutomatonExcept.try runningClock
let cl2 = handler e
(runningClock', _) <- once_ $ initClock cl2
safe $ runningClock' >>> arr (second Left)
return (catchingClock, initTime)
Left e -> (fmap (first (>>> arr (second Left))) . initClock) $ handler e
initClock (CatchClock cl1 handler) = safely $ do
e <- AutomatonExcept.try $ initClock cl1 >>> arr (second Right)
let cl2 = handler e
safe $ initClock cl2 >>> arr (second Left)

instance (GetClockProxy (CatchClock cl1 e cl2))

Expand Down Expand Up @@ -134,14 +122,13 @@ data Single m time tag e = Single
instance (TimeDomain time, MonadError e m) => Clock m (Single m time tag e) where
type Time (Single m time tag e) = time
type Tag (Single m time tag e) = tag
initClock Single {singleTag, getTime, exception} = do
initTime <- getTime
let runningClock = hoistS (errorT . runExceptT) $ runAutomatonExcept $ do
step_ (initTime, singleTag)
return exception
errorT :: (MonadError e m) => m (Either e a) -> m a
errorT = (>>= liftEither)
return (runningClock, initTime)
initClock Single {singleTag, getTime, exception} = hoistS (errorT . runExceptT) $ runAutomatonExcept $ do
initTime <- once_ getTime
step_ (initTime, singleTag)
return exception
where
errorT :: (MonadError e m) => m (Either e a) -> m a
errorT = (>>= liftEither)

-- * 'DelayException'

Expand Down
9 changes: 3 additions & 6 deletions rhine/src/FRP/Rhine/Clock/FixedStep.hs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,9 @@ instance (MonadSchedule m, Monad m) => Clock (ScheduleT Integer m) (FixedStep n)
type Tag (FixedStep n) = ()
initClock cl =
let step = stepsize cl
in return
( arr (const step)
>>> accumulateWith (+) 0
>>> arrM (\time -> wait step $> (time, ()))
, 0
)
in arr (const step)
>>> accumulateWith (+) 0
>>> arrM (\time -> wait step $> (time, ()))

instance GetClockProxy (FixedStep n)

Expand Down
6 changes: 1 addition & 5 deletions rhine/src/FRP/Rhine/Clock/Periodic.hs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,7 @@ instance
where
type Time (Periodic v) = Integer
type Tag (Periodic v) = ()
initClock cl =
return
( cycleS (theList cl) >>> withSideEffect wait >>> accumulateWith (+) 0 &&& arr (const ())
, 0
)
initClock cl = cycleS (theList cl) >>> withSideEffect wait >>> accumulateWith (+) 0 &&& arr (const ())

instance GetClockProxy (Periodic v)

Expand Down
35 changes: 16 additions & 19 deletions rhine/src/FRP/Rhine/Clock/Realtime.hs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
module FRP.Rhine.Clock.Realtime where

-- base
import Control.Arrow (arr)
import Control.Arrow (arr, returnA, (<<<))
import Control.Concurrent (threadDelay)
import Control.Monad (guard)
import Control.Monad.IO.Class
Expand Down Expand Up @@ -29,9 +29,9 @@ overwriteUTC :: (MonadIO m) => cl -> UTCClock m cl
overwriteUTC cl =
RescaledClockS
{ unscaledClockS = cl
, rescaleS = const $ do
now <- liftIO getCurrentTime
return (arrM $ \(_timePassed, tag) -> (,tag) <$> liftIO getCurrentTime, now)
, rescaleS = proc (_timePassed, tag) -> do
now <- constM $ liftIO getCurrentTime -< ()
returnA -< (now, tag)
}

{- | Rescale a clock to the UTC time domain.
Expand All @@ -45,9 +45,9 @@ addUTC :: (Real (Time cl), MonadIO m) => cl -> UTCClock m cl
addUTC cl =
RescaledClockS
{ unscaledClockS = cl
, rescaleS = const $ do
now <- liftIO getCurrentTime
return (arr $ \(timePassed, tag) -> (addUTCTime (realToFrac timePassed) now, tag), now)
, rescaleS = proc (timePassed, tag) -> do
initialTime <- cacheFirst <<< constM (liftIO getCurrentTime) -< ()
returnA -< (addUTCTime (realToFrac timePassed) initialTime, tag)
}

{- | Like 'UTCClock', but also output in the tag whether and by how much the target realtime was missed.
Expand Down Expand Up @@ -78,17 +78,14 @@ waitUTC :: (Real (Time cl), MonadIO m, Fractional (Diff (Time cl))) => cl -> Wai
waitUTC unscaledClockS =
RescaledClockS
{ unscaledClockS
, rescaleS = \_ -> do
initTime <- liftIO getCurrentTime
, rescaleS = hoistS liftIO $ proc (sinceInitTarget, tag) -> do
beforeSleep <- constM getCurrentTime -< ()
initTime <- cacheFirst -< beforeSleep
let
runningClock = arrM $ \(sinceInitTarget, tag) -> liftIO $ do
beforeSleep <- getCurrentTime
let
diff :: Rational
diff = toRational $ beforeSleep `diffUTCTime` initTime
remaining = toRational sinceInitTarget - diff
threadDelay $ round $ 1000000 * remaining
now <- getCurrentTime
return (now, (tag, guard (remaining > 0) >> return (fromRational remaining)))
return (runningClock, initTime)
diff :: Rational
diff = toRational $ beforeSleep `diffUTCTime` initTime
remaining = toRational sinceInitTarget - diff
arrM threadDelay -< round $ 1000000 * remaining
now <- constM getCurrentTime -< ()
returnA -< (now, (tag, guard (remaining > 0) >> return (fromRational remaining)))
}
Loading

0 comments on commit 2de85f0

Please sign in to comment.