{-# 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 Control.Monad.Trans.MSF.Except
import Control.Monad.Trans.MSF.Maybe (listToMaybeS, runMaybeT)
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