rhine-1.0: src/FRP/Rhine/Clock/FixedStep.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
{- |
Implements pure clocks ticking at
every multiple of a fixed number of steps,
and a deterministic schedule for such clocks.
-}
module FRP.Rhine.Clock.FixedStep where
-- base
import Data.Functor (($>))
import Data.Maybe (fromMaybe)
import GHC.TypeLits
-- vector-sized
import Data.Vector.Sized (Vector, fromList)
-- monad-schedule
import Control.Monad.Schedule.Class
import Control.Monad.Schedule.Trans (ScheduleT, wait)
-- rhine
import FRP.Rhine.Clock
import FRP.Rhine.Clock.Proxy
import FRP.Rhine.ResamplingBuffer
import FRP.Rhine.ResamplingBuffer.Collect
import FRP.Rhine.ResamplingBuffer.Util
{- | A pure (side effect free) clock with fixed step size,
i.e. ticking at multiples of 'n'.
The tick rate is in the type signature,
which prevents composition of signals at different rates.
-}
data FixedStep (n :: Nat) where
FixedStep :: KnownNat n => FixedStep n -- TODO Does the constraint bring any benefit?
-- | Extract the type-level natural number as an integer.
stepsize :: FixedStep n -> Integer
stepsize fixedStep@FixedStep = natVal fixedStep
instance (MonadSchedule m, Monad m) => Clock (ScheduleT Integer m) (FixedStep n) where
type Time (FixedStep n) = Integer
type Tag (FixedStep n) = ()
initClock cl =
let step = stepsize cl
in return
( arr (const step)
>>> accumulateWith (+) 0
>>> arrM (\time -> wait step $> (time, ()))
, 0
)
instance GetClockProxy (FixedStep n)
-- | A singleton clock that counts the ticks.
type Count = FixedStep 1
{- | Resample into a 'FixedStep' clock that ticks @n@ times slower,
by collecting all values into a vector.
-}
downsampleFixedStep ::
(KnownNat n, Monad m) =>
ResamplingBuffer m (FixedStep k) (FixedStep (n * k)) a (Vector n a)
downsampleFixedStep = collect >>-^ arr (fromList >>> assumeSize)
where
assumeSize = fromMaybe $ error "downsampleFixedStep: Internal error. Please report this as a bug: https://github.com/turion/rhine/issues"