-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Message passing concurrency as extensible-effect -- -- Please see the README on GitHub at -- https://github.com/sheyll/extensible-effects-concurrent#readme @package extensible-effects-concurrent @version 0.1.2.2 -- | The message passing effect. -- -- This module describes an abstract message passing effect, and a -- process effect, mimicking Erlang's process and message semantics. -- -- An implementation of a handler for these effects can be found in -- Dispatcher. module Control.Eff.Concurrent.MessagePassing -- | Each process is identified by a single process id, that stays constant -- throughout the life cycle of a process. Also, message sending relies -- on these values to address messages to processes. newtype ProcessId ProcessId :: Int -> ProcessId [_fromProcessId] :: ProcessId -> Int fromProcessId :: Iso' ProcessId Int -- | The process effect is the basis for message passing concurrency. This -- binds the semantics of a process with a process-id, and some process -- flags, and the ability to leave a process early with an error. data Process b [SelfPid] :: Process ProcessId [TrapExit] :: Bool -> Process () [GetTrapExit] :: Process Bool [RaiseError] :: String -> Process b -- | Returns the ProcessId of the current process. self :: Member Process r => Eff r ProcessId -- | Set the flag that controls a process reaction to exit messages from -- linked/monitored processes. trapExit :: Member Process r => Bool -> Eff r () -- | Return the trapExit flag. getTrapExit :: Member Process r => Eff r Bool -- | Thrown an error, can be caught by catchProcessError. raiseError :: Member Process r => String -> Eff r b -- | Catch and handle an error raised by raiseError. Works -- independent of the handler implementation. catchProcessError :: forall r w. Member Process r => (String -> Eff r w) -> Eff r w -> Eff r w -- | Like catchProcessError it catches raiseError, but -- instead of invoking a user provided handler, the result is wrapped -- into an Either. ignoreProcessError :: (HasCallStack, Member Process r) => Eff r a -> Eff r (Either String a) -- | An effect for sending and receiving messages. data MessagePassing b -- | Send a message to a process addressed by the ProcessId. Sending -- a message should **always succeed** and return **immediately**, even -- if the destination process does not exist, or does not accept messages -- of the given type. [SendMessage] :: Typeable m => ProcessId -> m -> MessagePassing Bool -- | Receive a message. This should block until an a message was received. -- The pure function may convert the incoming message into something, and -- the result is returned as Message value. Another reason why -- this function returns, is if a process control message was sent to the -- process. This can only occur from inside the runtime system, aka the -- effect handler implementation. (Currently there is one in -- Dispatcher.) [ReceiveMessage] :: forall e m. (Typeable m, Typeable (Message m)) => (m -> e) -> MessagePassing (Message e) -- | When a process invokes receiveMessage a value of this type is -- returned. There are more reasons that receiveMessage might -- return, one is that a message was sent to the process, another might -- be that in internal, handler specific, event occurred for which the -- process should wake-up. data Message m [ProcessControlMessage] :: String -> Message m [Message] :: m -> Message m -- | Send a message to a process addressed by the ProcessId. @see -- SendMessage. sendMessage :: forall o r. (HasCallStack, Member MessagePassing r, Typeable o) => ProcessId -> o -> Eff r Bool -- | Block until a message was received. Expect a message of the type -- annotated by the Proxy. Depending on trapExit, this will -- raiseError. @see ReceiveMessage. receiveMessage :: forall o r. (HasCallStack, Member MessagePassing r, Member Process r, Typeable o) => Proxy o -> Eff r (Message o) instance Data.Traversable.Traversable Control.Eff.Concurrent.MessagePassing.Message instance Data.Foldable.Foldable Control.Eff.Concurrent.MessagePassing.Message instance GHC.Classes.Ord m => GHC.Classes.Ord (Control.Eff.Concurrent.MessagePassing.Message m) instance GHC.Classes.Eq m => GHC.Classes.Eq (Control.Eff.Concurrent.MessagePassing.Message m) instance GHC.Show.Show m => GHC.Show.Show (Control.Eff.Concurrent.MessagePassing.Message m) instance GHC.Base.Functor Control.Eff.Concurrent.MessagePassing.Message instance GHC.Real.Real Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Real.Integral Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Enum.Enum Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Num.Num Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Enum.Bounded Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Classes.Ord Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Classes.Eq Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Read.Read Control.Eff.Concurrent.MessagePassing.ProcessId instance GHC.Show.Show Control.Eff.Concurrent.MessagePassing.ProcessId -- | Type safe server API processes module Control.Eff.Concurrent.GenServer -- | This data family defines an API implemented by a server. The first -- parameter is the API index and the second parameter (the * -- -> *) data Synchronicity Synchronous :: Type -> Synchronicity Asynchronous :: Synchronicity data ApiHandler p r e ApiHandler :: (Typeable p, Typeable (Api p 'Asynchronous), HasCallStack) => Api p 'Asynchronous -> Eff r e -> (forall x. (Typeable p, Typeable (Api p ( 'Synchronous x)), Typeable x, HasCallStack) => Api p ( 'Synchronous x) -> (x -> Eff r Bool) -> Eff r e) -> (Typeable p, HasCallStack) => String -> Eff r () -> ApiHandler p r e newtype Server genServerModule Server :: ProcessId -> Server genServerModule [_fromServer] :: Server genServerModule -> ProcessId fromServer :: forall genServerModule_agQU genServerModule_ah0L. Iso (Server genServerModule_agQU) (Server genServerModule_ah0L) ProcessId ProcessId proxyAsServer :: proxy genServerModule -> ProcessId -> Server genServerModule asServer :: forall genServerModule. ProcessId -> Server genServerModule cast :: forall r o. (HasCallStack, Member MessagePassing r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r Bool cast_ :: forall r o. (HasCallStack, Member MessagePassing r, Typeable o, Typeable (Api o 'Asynchronous)) => Server o -> Api o 'Asynchronous -> Eff r () call :: forall result genServerModule r. (Member MessagePassing r, Member Process r, Typeable genServerModule, Typeable (Api genServerModule ( 'Synchronous result)), Typeable result, HasCallStack) => Server genServerModule -> Api genServerModule ( 'Synchronous result) -> Eff r (Message result) serve :: forall r p e. (Typeable p, Member MessagePassing r, Member Process r, HasCallStack) => ApiHandler p r e -> Eff r (Message e) serve_ :: forall r p. (Typeable p, Member MessagePassing r, Member Process r, HasCallStack) => ApiHandler p r () -> Eff r () unhandledCallError :: (Show (Api p ( 'Synchronous x)), Typeable p, Typeable (Api p ( 'Synchronous x)), Typeable x, HasCallStack, Member Process r) => Api p ( 'Synchronous x) -> (x -> Eff r Bool) -> Eff r e unhandledCastError :: (Show (Api p 'Asynchronous), Typeable p, Typeable (Api p 'Asynchronous), HasCallStack, Member Process r) => Api p 'Asynchronous -> Eff r e instance GHC.Classes.Ord (Control.Eff.Concurrent.GenServer.Server genServerModule) instance GHC.Classes.Eq (Control.Eff.Concurrent.GenServer.Server genServerModule) instance GHC.Read.Read (Control.Eff.Concurrent.GenServer.Server genServerModule) instance Data.Typeable.Internal.Typeable genServerModule => GHC.Show.Show (Control.Eff.Concurrent.GenServer.Server genServerModule) -- | Add-ons to Exception module Control.Eff.ExceptionExtra -- | Catch an exception and return it in an Either. try :: forall e r a. Member (Exc e) r => Eff r a -> Eff r (Either e a) -- | Lift an IO action and catch all error using try then wrap the -- Exception using a given wrapper function and rethrow it using -- throwError. liftRethrow :: forall e r a. (Exception e, SetMember Lift (Lift IO) r, Member (Exc e) r) => (SomeException -> e) -> IO a -> Eff r a -- | Run an effect with exceptions like runError and rethrow it as -- SomeException using throw runErrorRethrowIO :: forall e r a. (Exception e, SetMember Lift (Lift IO) r) => Eff (Exc e : r) a -> Eff r a module Control.Eff.Interactive data Interaction a [PrintLine] :: String -> Interaction () [ReadLine] :: (String -> a) -> Interaction a [Step] :: Interaction () printLine :: (Member (Program Interaction) r, HasCallStack) => String -> Eff r () printStep :: (Member (Program Interaction) r, HasCallStack) => String -> Eff r () promptStep :: (Member (Program Interaction) r, HasCallStack) => String -> (String -> a) -> Eff r a step :: (Member (Program Interaction) r, HasCallStack) => Eff r () class Interactive f singleSteps :: (Interactive f, Member (Program Interaction) r, HasCallStack) => f a -> Eff r a interactiveProgram :: (HasCallStack, Member (Program Interaction) r, Interactive f) => Eff (Program f : r) a -> Eff r a runInteractionIOE :: (SetMember Lift (Lift IO) r, HasCallStack) => Eff (Program Interaction : r) a -> Eff r a runInteractionIO :: Eff '[Program Interaction, Lift IO] a -> IO a -- | An extensible effect that wraps MonadLog into an extensible -- effect. module Control.Eff.Log -- | Handle Logs effects using LoggingT Handlers. handleLogsWith :: forall m r message a. (Monad m, SetMember Lift (Lift m) r) => Eff (Logs message : r) a -> (forall b. (Handler m message -> m b) -> m b) -> Eff r a -- | The Effect type to wrap MonadLog. This is a data Logs message a [LogMessageFree] :: (forall n. Monoid n => (message -> n) -> n) -> Logs message () -- | Effectful version of the strange logMessageFree -- function. logMessageFreeEff :: Member (Logs message) r => (forall n. Monoid n => (message -> n) -> n) -> Eff r () -- | Effectful version of the logMessage function. logMsg :: Member (Logs m) r => m -> Eff r () -- | Input queue for a concurrent logger. data LogChannel message -- | Enqueue a log message into a log channel logChannelPutIO :: LogChannel message -> message -> IO () -- | Send the log messages to a LogChannel. forwardLogsToChannel :: forall r message a. (SetMember Lift (Lift IO) r) => LogChannel message -> Eff (Logs message : r) a -> Eff r a -- | Fork LogChannel backed by a process that repeatedly receives -- log messages sent by forwardLogstochannel or -- logChannelPutIO. The process logs by invoken the given IO -- action. To stop and terminate a LogChannel invoke -- joinLogChannel. forkLogChannel :: forall message. (message -> IO ()) -> Maybe message -> IO (LogChannel message) -- | Close a log channel. Subsequent loggin requests will no be handled any -- more. joinLogChannel :: Maybe message -> LogChannel message -> IO () -- | Wrap LogChannel creation and destruction around a monad action -- in brackety manner. logChannelBracket :: Maybe message -> Maybe message -> (LogChannel message -> IO a) -> LoggingT message IO a -- | Implement Erlang style message passing concurrency. -- -- This handles the MessagePassing and Process effects, -- using TQueues and forkIO. -- -- This aims to be a pragmatic implementation, so even logging is -- supported. -- -- At the core is a main process that enters runMainProcess -- and creates all of the internal state stored in TVars to manage -- processes with message queues. -- -- The Eff handler for Process and MessagePassing -- use are implemented and available through spawn. -- -- spawn uses forkFinally and TQueues and tries to -- catch most exceptions. module Control.Eff.Concurrent.Dispatcher -- | This is the main entry point to running a message passing concurrency -- application. This function takes a ProcIO effect and a -- LogChannel for concurrent logging. runMainProcess :: Eff ProcIO a -> LogChannel String -> IO a -- | Start the message passing concurrency system then execute a -- ProcIO effect. All logging is sent to standard output. defaultMain :: Eff ProcIO a -> IO a spawn :: HasDispatcherIO r => Eff ProcIO () -> Eff r ProcessId -- | A sum-type with errors that can occur when dispatching messages. data DispatcherError -- | A process message queue contained a bad message and the Dynamic -- value could not be converted to the expected value using -- fromDynamic. UnhandledMessageReceived :: Dynamic -> ProcessId -> DispatcherError -- | No ProcessInfo was found for a ProcessId during internal -- processing. NOTE: This is **ONLY** caused by internal errors, probably -- by an incorrect MessagePassing handler in this module. -- **Sending a message to a process ALWAYS succeeds!** Even if the -- process does not exist. ProcessNotFound :: ProcessId -> DispatcherError -- | A process called raiseError. ProcessException :: String -> ProcessId -> DispatcherError -- | An action was not performed while the dispatcher was exiting. DispatcherShuttingDown :: DispatcherError -- | SomeException was caught while dispatching messages. LowLevelIOException :: SomeException -> DispatcherError -- | The concrete list of Effects for this scheduler implementation. -- @see HasDispatcherIO type DispatcherIO = '[Exc DispatcherError, Reader DispatcherVar, Logs String, Lift IO] -- | An alias for the constraints for the effects essential to this -- dispatcher implementation, i.e. these effects allow spawning -- new Processes. @see DispatcherIO type HasDispatcherIO r = (HasCallStack, SetMember Lift (Lift IO) r, Member (Exc DispatcherError) r, Member (Logs String) r, Member (Reader DispatcherVar) r) -- | The concrete list of Effects that provide MessagePassing -- and Processes ontop of DispatcherIO type ProcIO = ConsProcIO DispatcherIO instance GHC.Show.Show Control.Eff.Concurrent.Dispatcher.DispatcherError instance Control.Monad.Log.MonadLog GHC.Base.String (Control.Eff.Eff Control.Eff.Concurrent.Dispatcher.ProcIO) instance GHC.Exception.Exception Control.Eff.Concurrent.Dispatcher.DispatcherError instance GHC.Show.Show Control.Eff.Concurrent.Dispatcher.ProcessInfo -- | Observer Effects -- -- This module supports the implementation of observers and observables. -- One more concrete perspective might be to understand observers as -- event listeners and observables as event sources. The tools in this -- module are tailored towards Api endpoints module Control.Eff.Concurrent.Observer -- | An Api index that support observation of the another Api -- that is Observable. class (Typeable p, Observable o) => Observer p o -- | Wrap the Observation and the ProcessId (i.e. the -- Server) that caused the observation into a Api value -- that the Observable understands. observationMessage :: Observer p o => Server o -> Observation o -> Api p 'Asynchronous -- | An Api index that supports registration and de-registration of -- Observers. class (Typeable o, Typeable (Observation o)) => Observable o where { data family Observation o; } -- | Return the Api value for the cast_ that registeres an -- observer registerObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous -- | Return the Api value for the cast_ that de-registeres an -- observer forgetObserverMessage :: Observable o => SomeObserver o -> Api o 'Asynchronous -- | Send an Observation to an Observer notifyObserver :: (Member Process r, Member MessagePassing r, Observable o, Observer p o, HasCallStack) => Server p -> Server o -> Observation o -> Eff r () -- | Send the registerObserverMessage registerObserver :: (Member Process r, Member MessagePassing r, Observable o, Observer p o, HasCallStack) => Server p -> Server o -> Eff r () -- | Send the forgetObserverMessage forgetObserver :: (Member Process r, Member MessagePassing r, Observable o, Observer p o) => Server p -> Server o -> Eff r () -- | An existential wrapper around a Server of an Observer. -- Needed to support different types of observers to observe the same -- Observable in a general fashion. data SomeObserver o [SomeObserver] :: (Show (Server p), Typeable p, Observer p o) => Server p -> SomeObserver o -- | Send an Observation to SomeObserver. notifySomeObserver :: (Member Process r, Member MessagePassing r, Observable o, HasCallStack) => Server o -> Observation o -> SomeObserver o -> Eff r () -- | Internal state for manageobservers data Observers o -- | Keep track of registered Observers Observers can be added and -- removed, and an Observation can be sent to all registerd -- observers at once. manageObservers :: Eff (State (Observers o) : r) a -> Eff r a -- | Add an Observer to the Observers managed by -- manageObservers. addObserver :: (Member MessagePassing r, Member (State (Observers o)) r, Observable o) => SomeObserver o -> Eff r () -- | Delete an Observer from the Observers managed by -- manageObservers. removeObserver :: (Member MessagePassing r, Member (State (Observers o)) r, Observable o) => SomeObserver o -> Eff r () -- | Send an Observation to all SomeObservers in the -- Observers state. notifyObservers :: forall o r. (Observable o, Member MessagePassing r, Member Process r, Member (State (Observers o)) r) => Observation o -> Eff r () -- | An Observer that dispatches the observations to an effectful -- callback. data CallbackObserver o -- | Start a new process for an Observer that dispatches all -- observations to an effectful callback. spawnCallbackObserver :: forall o r. (HasDispatcherIO r, Typeable o, Show (Observation o), Observable o) => (Server o -> Observation o -> Eff ProcIO Bool) -> Eff r (Server (CallbackObserver o)) instance GHC.Show.Show (Control.Eff.Concurrent.Observer.SomeObserver o) instance GHC.Show.Show (Control.Eff.Concurrent.Observer.Observation o) => GHC.Show.Show (Control.Eff.Concurrent.GenServer.Api (Control.Eff.Concurrent.Observer.CallbackObserver o) r) instance Control.Eff.Concurrent.Observer.Observable o => Control.Eff.Concurrent.Observer.Observer (Control.Eff.Concurrent.Observer.CallbackObserver o) o instance GHC.Classes.Ord (Control.Eff.Concurrent.Observer.SomeObserver o) instance GHC.Classes.Eq (Control.Eff.Concurrent.Observer.SomeObserver o)