{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE TypeFamilies #-} import FRP.Rhine import FRP.Rhine.Clock.Realtime.Millisecond import FRP.Rhine.Schedule.Concurrently import FRP.Rhine.ResamplingBuffer.Collect -- | Create a simple message containing the time stamp since program start, -- for each tick of the clock. -- Since 'createMessage' works for arbitrary clocks (and doesn't need further input data), -- it is a 'Behaviour'. -- @td@ is the 'TimeDomain' of any clock used to sample, -- and it needs to be constrained in order for time differences -- to have a 'Show' instance. createMessage :: (Monad m, Show (Diff td)) => String -> Behaviour m td String createMessage str = timeInfoOf sinceStart >-> arr show >-> arr (("Clock " ++ str ++ " has ticked at: ") ++) -- | Output a message /every second/ (= every 1000 milliseconds). -- Let us assume we want to assure that 'printEverySecond' -- is only called every second, -- then we constrain its type signature with the clock @Millisecond 1000@. printEverySecond :: Show a => SyncSF IO (Millisecond 1000) a () printEverySecond = arrMSync print -- | Specialise 'createMessage' to a specific clock. ms500 :: SyncSF IO (Millisecond 500) () String ms500 = createMessage "500 MS" ms1200 :: SyncSF IO (Millisecond 1200) () String ms1200 = createMessage "1200 MS" -- | Create messages every 500 ms and every 1200 ms, -- collecting all of them in a list, -- which is output every second. main :: IO () main = flow $ ms500 @@ waitClock **@ concurrently @** ms1200 @@ waitClock >-- collect -@- concurrently --> printEverySecond @@ waitClock -- | Uncomment the following for a type error (the clocks don't match): -- typeError = ms500 >>> printEverySecond