{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE TypeSynonymInstances #-}
module FRP.Rhine.Clock.Periodic (Periodic (Periodic)) where
import Control.Monad (forever)
import Data.List.NonEmpty hiding (unfold)
import Data.Maybe (fromMaybe)
import GHC.TypeLits (Nat, KnownNat, natVal)
import Data.MonadicStreamFunction
import FRP.Rhine.Clock
import Control.Monad.Schedule
data Periodic (v :: [Nat]) where
Periodic :: Periodic (n : ns)
instance (Monad m, NonemptyNatList v)
=> Clock (ScheduleT Integer m) (Periodic v) where
type Time (Periodic v) = Integer
type Tag (Periodic v) = ()
initClock cl = return
( cycleS (theList cl) >>> withSideEffect wait >>> sumS &&& arr (const ())
, 0
)
data HeadClProxy (n :: Nat) where
HeadClProxy :: Periodic (n : ns) -> HeadClProxy n
headCl :: KnownNat n => Periodic (n : ns) -> Integer
headCl cl = natVal $ HeadClProxy cl
tailCl :: Periodic (n1 : n2 : ns) -> Periodic (n2 : ns)
tailCl Periodic = Periodic
class NonemptyNatList (v :: [Nat]) where
theList :: Periodic v -> NonEmpty Integer
instance KnownNat n => NonemptyNatList '[n] where
theList cl = headCl cl :| []
instance (KnownNat n1, KnownNat n2, NonemptyNatList (n2 : ns))
=> NonemptyNatList (n1 : n2 : ns) where
theList cl = headCl cl <| theList (tailCl cl)
cycleS :: Monad m => NonEmpty a -> MSF m () a
cycleS as = unfold (second (fromMaybe as) . uncons) as