{- A simple ticking clock -} module Clock( Clock, -- the Clock type newClock, -- create a new clock start, -- starts or restarts the clock stop, -- stop the clock (it can be restarted) getTime -- read the clock time at the last tick (doesn't block) ) where import System.IO.Unsafe import Data.IORef import Events import Destructible import Channels import Time import Control.Concurrent -- The type representing the clok data Clock = Clock { ch :: Channel Bool, tr :: IORef TimeDiff, halt :: IO () } -- create a new clock -- Arguments are the time between ticks, -- and an IO action which happens every tick. newClock :: Int-> (TimeDiff-> IO a)-> IO Clock newClock d tick = do c <- newChannel t0 <- getClockTime r <- newIORef (diffClockTimes t0 t0) let clock' :: Event () clock' = do b<- receive c if b then do t0<- always getClockTime clock t0 else clock' clock :: ClockTime-> Event () clock t0 = clock' +> do always (do threadDelay d t1 <- getClockTime let delta= diffClockTimes t1 t0 writeIORef r delta tick delta return ()) clock t0 k <- spawnEvent clock' return Clock {ch = c, tr= r, halt= k} start :: Clock-> Event () start c = send (ch c) True stop :: Clock-> Event () stop c = send (ch c) False getTime :: Clock-> IO TimeDiff getTime c = readIORef (tr c) instance Destroyable Clock where destroy c = halt c