{-# LANGUAGE Arrows #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeFamilies #-}
module FRP.Rhine.ClSF.Util where
import Control.Arrow
import Control.Category (Category)
import qualified Control.Category (id)
import Data.Maybe (fromJust)
import Data.Monoid (Last (Last), getLast)
import Data.Sequence
import Control.Monad.Trans.Reader (ask, asks)
import Control.Monad.Trans.MSF.Reader (readerS)
import Data.MonadicStreamFunction (constM, sumFrom, iPre, feedback)
import Data.MonadicStreamFunction.Instances.VectorSpace ()
import Data.VectorSpace
import FRP.Rhine.ClSF.Core
import FRP.Rhine.ClSF.Except
timeInfo :: Monad m => ClSF m cl a (TimeInfo cl)
timeInfo = constM ask
timeInfoOf :: Monad m => (TimeInfo cl -> b) -> ClSF m cl a b
timeInfoOf f = constM $ asks f
sinceLastS :: Monad m => ClSF m cl a (Diff (Time cl))
sinceLastS = timeInfoOf sinceLast
sinceInitS :: Monad m => ClSF m cl a (Diff (Time cl))
sinceInitS = timeInfoOf sinceInit
absoluteS :: Monad m => ClSF m cl a (Time cl)
absoluteS = timeInfoOf absolute
tagS :: Monad m => ClSF m cl a (Tag cl)
tagS = timeInfoOf tag
sinceStart :: (Monad m, TimeDomain time) => BehaviourF m time a (Diff time)
sinceStart = absoluteS >>> proc time -> do
startTime <- keepFirst -< time
returnA -< time `diffTime` startTime
infixr 6 >->
(>->) :: Category cat
=> cat a b
-> cat b c
-> cat a c
(>->) = (>>>)
infixl 6 <-<
(<-<) :: Category cat
=> cat b c
-> cat a b
-> cat a c
(<-<) = (<<<)
arr_ :: Arrow a => b -> a c b
arr_ = arr . const
clId :: Monad m => ClSF m cl a a
clId = Control.Category.id
integralFrom
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> v -> BehaviorF m td v v
integralFrom v0 = proc v -> do
_sinceLast <- timeInfoOf sinceLast -< ()
sumFrom v0 -< _sinceLast *^ v
integral
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> BehaviorF m td v v
integral = integralFrom zeroVector
derivativeFrom
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> v -> BehaviorF m td v v
derivativeFrom v0 = proc v -> do
vLast <- iPre v0 -< v
TimeInfo {..} <- timeInfo -< ()
returnA -< (v ^-^ vLast) ^/ sinceLast
derivative
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> BehaviorF m td v v
derivative = derivativeFrom zeroVector
threePointDerivativeFrom
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> v
-> BehaviorF m td v v
threePointDerivativeFrom v0 = proc v -> do
dv <- derivativeFrom v0 -< v
dv' <- iPre zeroVector -< dv
returnA -< (dv ^+^ dv') ^/ 2
threePointDerivative
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> BehaviorF m td v v
threePointDerivative = threePointDerivativeFrom zeroVector
weightedAverageFrom
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> v
-> BehaviorF m td (v, Groundfield v) v
weightedAverageFrom v0 = feedback v0 $ proc ((v, weight), vAvg) -> do
let
vAvg' = weight *^ vAvg ^+^ (1 - weight) *^ v
returnA -< (vAvg', vAvg')
averageFrom
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> v
-> Diff td
-> BehaviorF m td v v
averageFrom v0 t = proc v -> do
TimeInfo {..} <- timeInfo -< ()
let
weight = exp $ - (sinceLast / t)
weightedAverageFrom v0 -< (v, weight)
average
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
average = averageFrom zeroVector
averageLinFrom
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> v
-> Diff td
-> BehaviourF m td v v
averageLinFrom v0 t = proc v -> do
TimeInfo {..} <- timeInfo -< ()
let
weight = t / (sinceLast + t)
weightedAverageFrom v0 -< (v, weight)
averageLin
:: ( Monad m, VectorSpace v
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
averageLin = averageLinFrom zeroVector
lowPass
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
lowPass = average
highPass
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
highPass t = clId ^-^ lowPass t
bandPass
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
bandPass t = lowPass t >>> highPass t
bandStop
:: ( Monad m, VectorSpace v
, Floating (Groundfield v)
, Groundfield v ~ Diff td)
=> Diff td
-> BehaviourF m td v v
bandStop t = clId ^-^ bandPass t
keepFirst :: Monad m => ClSF m cl a a
keepFirst = safely $ do
a <- try throwS
safe $ arr $ const a
historySince
:: (Monad m, Ord (Diff (Time cl)), TimeDomain (Time cl))
=> Diff (Time cl)
-> ClSF m cl a (Seq (TimeInfo cl, a))
historySince dTime = readerS $ accumulateWith appendValue empty
where
appendValue (ti, a) tias = takeWhileL (recentlySince ti) $ (ti, a) <| tias
recentlySince ti (ti', _) = diffTime (absolute ti) (absolute ti') < dTime
delayBy
:: (Monad m, Ord (Diff (Time cl)), TimeDomain (Time cl))
=> Diff (Time cl)
-> ClSF m cl a a
delayBy dTime = historySince dTime >>> arr (viewr >>> safeHead) >>> lastS undefined >>> arr snd
where
safeHead EmptyR = Nothing
safeHead (_ :> a) = Just a
timer
:: ( Monad m
, TimeDomain td
, Ord (Diff td)
)
=> Diff td
-> BehaviorF (ExceptT () m) td a (Diff td)
timer diff = proc _ -> do
time <- sinceStart -< ()
_ <- throwOn () -< time > diff
returnA -< time
timer_
:: ( Monad m
, TimeDomain td
, Ord (Diff td)
)
=> Diff td
-> BehaviorF (ExceptT () m) td a ()
timer_ diff = timer diff >>> arr (const ())
scaledTimer
:: ( Monad m
, TimeDomain td
, Fractional (Diff td)
, Ord (Diff td)
)
=> Diff td
-> BehaviorF (ExceptT () m) td a (Diff td)
scaledTimer diff = timer diff >>> arr (/ diff)
lastS :: Monad m => a -> MSF m (Maybe a) a
lastS a = arr Last >>> mappendFrom (Last (Just a)) >>> arr (getLast >>> fromJust)