{- - ``Control/Monad/Event/Classes'' -} {-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies #-} module Control.Monad.Event.Classes where import Control.Monad.Event.Internal.Types import Text.PrettyPrint.HughesPJ -- |A type-class for monads with a concept of time. That concept need not -- necessarily meet any prior conditions - not even an Eq instance. class Monad m => MonadTime m t | m -> t where getCurrentTime :: m t -- |A monad in which there is a concept of running and not-running and -- unrestricted operations for switching between them. class Monad m => MonadSimControl m where resumeSimulation :: m () pauseSimulation :: m () isSimulationRunning :: m Bool -- |A monad in which there is a concept of an \"event\" - an action with a -- sort of a special status, which can be described for humans and can be -- otherwise manipulated in monads implementing the classes to follow. class Monad m => MonadEvent m e | e -> m where describeEvent :: e -> m Doc describeEvent e = return (text "Undocumented event - implement describeEvent") runEvent :: e -> m () -- | A monad which can schedule events for later execution. For obvious -- reasons, such a monad must also have a concept of events (covering the -- event that the user is trying to schedule) and a concept of time. class (MonadEvent m e, MonadTime m t) => ScheduleEvent m t e | m -> t where -- |Schedule an event for execution at a time. -- The meaning of \"time\" is left entirely up to the -- implementor, however it will generally be the case that time is -- an instance of 'Num' and/or is totally ordered in the usual way. -- -- Returns an 'EventID' that can be used to identify the event -- if needed later (for example, to cancel it). scheduleEventAt :: t -> e -> m EventID -- |schedule an event to run at the current time. This does not -- constitute a promise to execute immediately or in any particular -- order relative to other events that have been or will be -- scheduled for the current time. -- -- If an implementor has a time type which is an instance of 'Num', then -- 'doNext' should be equivalent to 'scheduleEventIn' 0 - unless the -- monad's documentation clearly warns to the contrary in a really big -- typeface. ; ) Note that this clause may change to also strongly -- suggest that 'doNext' put its event at the very front of the queue -- (ie, before any other events already scheduled for the current time). doNext :: e -> m () doNext e = do now <- getCurrentTime scheduleEventAt now e return () -- |schedule an event at an absolute time (see 'scheduleEventIn') scheduleEventIn :: (ScheduleEvent m t e, Num t) => t -> e -> m EventID scheduleEventIn dt e = do now <- getCurrentTime let t = now + dt scheduleEventAt t e -- | A monad in which an event (presumably one previously scheduled) -- can be canceled. class MonadTime m t => CancelEvent m t | m -> t where -- |Cancel an event given its 'EventID'. If successful (and -- if the monad's implementation allows it), an 'EventDescriptor' -- (an existential wrapper describing an event, its ID, and -- the time at which it would have run) containing the -- canceled event is returned. cancelEvent :: EventID -> m (Maybe (EventDescriptor m t)) -- | A monad in which an 'EventDescriptor' for the currently-executing -- event, if any, can be obtained. class MonadTime m t => GetCurrentEvent m t | m -> t where getCurrentEvent :: m (Maybe (EventDescriptor m t)) -- | A monad in which the currently executing event can be rescheduled. -- Note that calling 'retryEventAt' does not terminate the currently -- executing event - although perhaps it should. Until a more permanent -- decision is made, it's probably best to make 'retryEventAt' the last -- action of an event when it is used, to minimize impact of future changes. class MonadTime m t => RetryEvent m t | m -> t where retryEventAt :: t -> m EventID -- |retry the currently-executing event at an absolute time (see 'retryEventIn') retryEventIn :: (RetryEvent m t, Num t) => t -> m EventID retryEventIn dt = do now <- getCurrentTime let t = now + dt retryEventAt t -- |A monad in which information about the event queue can be retrieved. class MonadTime m t => MonadEventQueueInfo m t | m -> t where -- |Return the number of events currently scheduled. eventQueueSize :: m Int -- |Return a list of (some or all of) the events coming up. -- There is no obligation on the part of the monad to provide -- anything at all. eventQueueContents :: m [EventDescriptor m t]