-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | composing programs with multithreading, events and distributed computing -- -- See http://github.com/agocorona/transient Distributed -- primitives are in the transient-universe package. Web primitives are -- in the axiom package. @package transient @version 0.7.0.0 -- | See http://github.com/transient-haskell/transient Everything in -- this module is exported in order to allow extensibility. module Transient.Internals tshow :: a -> x -> x (!>) :: a -> b -> a tr :: Monad m => b -> m () type StateIO = StateT EventF IO newtype TransIO a Transient :: StateIO (Maybe a) -> TransIO a [runTrans] :: TransIO a -> StateIO (Maybe a) type SData = () type EventId = Int type TransientIO = TransIO data LifeCycle Alive :: LifeCycle Parent :: LifeCycle Listener :: LifeCycle Dead :: LifeCycle -- | EventF describes the context of a TransientIO computation: data EventF EventF :: Maybe SData -> TransIO a -> [b -> TransIO b] -> Map TypeRep SData -> Int -> ThreadId -> Bool -> Maybe EventF -> MVar [EventF] -> Maybe (IORef Int) -> IORef (LifeCycle, ByteString) -> ParseContext -> ExecMode -> EventF -- | Not yet consumed result (event) from the last asynchronous computation [event] :: EventF -> Maybe SData [xcomp] :: EventF -> TransIO a -- | List of continuations [fcomp] :: EventF -> [b -> TransIO b] -- | State data accessed with get or put operations [mfData] :: EventF -> Map TypeRep SData [mfSequence] :: EventF -> Int [threadId] :: EventF -> ThreadId -- | When True, threads are not killed using kill primitives [freeTh] :: EventF -> Bool -- | The parent of this thread [parent] :: EventF -> Maybe EventF -- | Forked child threads, used only when freeTh is False [children] :: EventF -> MVar [EventF] -- | Maximum number of threads that are allowed to be created [maxThread] :: EventF -> Maybe (IORef Int) -- | Label the thread with its lifecycle state and a label string [labelth] :: EventF -> IORef (LifeCycle, ByteString) [parseContext] :: EventF -> ParseContext [execMode] :: EventF -> ExecMode data ParseContext ParseContext :: TransIO (StreamData ByteString) -> ByteString -> IORef Bool -> ParseContext [more] :: ParseContext -> TransIO (StreamData ByteString) [buffer] :: ParseContext -> ByteString [done] :: ParseContext -> IORef Bool -- | To define primitives for all the transient monads: TransIO, Cloud and -- Widget class MonadState EventF m => TransMonad m -- | Run a computation in the underlying state monad. it is a little -- lighter and performant and it should not contain advanced effects -- beyond state. noTrans :: StateIO x -> TransIO x -- | filters away the Nothing responses of the State monad. in principle -- the state monad should return a single response, but, for performance -- reasons, it can run inside elements of transient monad (using -- runTrans) which may produce many results liftTrans :: StateIO (Maybe b) -> TransIO b emptyEventF :: ThreadId -> IORef (LifeCycle, ByteString) -> MVar [EventF] -> EventF -- | Run a transient computation with a default initial state runTransient :: TransIO a -> IO (Maybe a, EventF) -- | Run a transient computation with a given initial state runTransState :: EventF -> TransIO x -> IO (Maybe x, EventF) emptyIfNothing :: Maybe a -> TransIO a -- | Get the continuation context: closure, continuation, state, child -- threads etc getCont :: TransIO EventF -- | Run the closure and the continuation using the state data of the -- calling thread runCont :: EventF -> StateIO (Maybe a) -- | Run the closure and the continuation using its own state data. runCont' :: EventF -> IO (Maybe a, EventF) -- | Warning: Radically untyped stuff. handle with care getContinuations :: StateIO [a -> TransIO b] -- | Compose a list of continuations. compose :: [a -> TransIO a] -> a -> TransIO b -- | Run the closure (the x in 'x >>= f') of the current -- bind operation. runClosure :: EventF -> StateIO (Maybe a) -- | Run the continuation (the f in 'x >>= f') of the -- current bind operation with the current state. runContinuation :: EventF -> a -> StateIO (Maybe b) -- | Save a closure and a continuation (x and f in 'x -- >>= f'). setContinuation :: TransIO a -> (a -> TransIO b) -> [c -> TransIO c] -> StateIO () -- | Save a closure and continuation, run the closure, restore the old -- continuation. | NOTE: The old closure is discarded. withContinuation :: b -> TransIO a -> TransIO a -- | Restore the continuations to the provided ones. | NOTE: Events are -- also cleared out. restoreStack :: TransMonad m => [a -> TransIO a] -> m () -- | Run a chain of continuations. WARNING: It is up to the programmer to -- assure that each continuation typechecks with the next, and that the -- parameter type match the input of the first continuation. NOTE: -- Normally this makes sense to stop the current flow with stop -- after the invocation. runContinuations :: [a -> TransIO b] -> c -> TransIO d data ExecMode Remote :: ExecMode Parallel :: ExecMode Serial :: ExecMode -- | stop the current computation and does not execute any alternative -- computation fullStop :: TransIO stop mappendt :: (Applicative f, Monoid b) => f b -> f b -> f b readWithErr :: (Typeable a, Read a) => Int -> String -> IO [(a, String)] newtype ParseError ParseError :: String -> ParseError read' :: (Typeable p, Read p) => String -> p readsPrec' :: (Typeable a, Read a) => Int -> String -> [(a, String)] -- | A synonym of empty that can be used in a monadic expression. It -- stops the computation, which allows the next computation in an -- Alternative (<|>) composition to run. stop :: Alternative m => m stopped class AdditionalOperators m -- | Run m a discarding its result before running m b. (**>) :: AdditionalOperators m => m a -> m b -> m b -- | Run m b discarding its result, after the whole task set m -- a is done. (<**) :: AdditionalOperators m => m a -> m b -> m a atEnd' :: AdditionalOperators m => m a -> m b -> m a -- | Run m b discarding its result, once after each task in m -- a, and once again after the whole task set is done. (<***) :: AdditionalOperators m => m a -> m b -> m a atEnd :: AdditionalOperators m => m a -> m b -> m a infixl 4 <*** infixl 4 <** infixl 4 **> -- | Run b once, discarding its result when the first task in task -- set a has finished. Useful to start a singleton task after -- the first task has been setup. (<|) :: TransIO a -> TransIO b -> TransIO a -- | Set the current closure and continuation for the current statement setEventCont :: TransIO a -> (a -> TransIO b) -> StateIO () -- | Reset the closure and continuation. Remove inner binds than the -- previous computations may have stacked in the list of continuations. -- resetEventCont :: Maybe a -> EventF -> StateIO () resetEventCont :: MonadState EventF m => Maybe t -> m () -- | Total variant of tail that returns an empty list when given an -- empty list. tailsafe :: [a] -> [a] waitQSemB :: (Ord a, Num a) => Bool -> IORef a -> IO Bool signalQSemB :: Num a => IORef a -> IO () -- | Sets the maximum number of threads that can be created for the given -- task set. When set to 0, new tasks start synchronously in the current -- thread. New threads are created by parallel, and APIs that use -- parallel. threads :: Int -> TransIO a -> TransIO a cloneInChild :: (MonadState EventF m, MonadIO m) => [Char] -> m EventF removeChild :: (MonadIO m, TransMonad m) => m () -- | Terminate all the child threads in the given task set and continue -- execution in the current thread. Useful to reap the children when a -- task is done, restart a task when a new event happens etc. oneThread :: TransIO a -> TransIO a -- | Add a label to the current passing threads so it can be printed by -- debugging calls like showThreads labelState :: (MonadIO m, TransMonad m) => ByteString -> m () -- | return the threadId associated with an state (you can see all of them -- with the console option ps) threadState :: ByteString -> TransIO ThreadId -- | kill the thread subtree labeled as such (you can see all of them with -- the console option ps) killState :: (MonadIO m, Alternative m, MonadState EventF m) => ByteString -> m () printBlock :: MVar () -- | Show the tree of threads hanging from the state. showThreads :: MonadIO m => EventF -> m () -- | Return the state of the thread that initiated the transient -- computation topState :: TransIO EventF topState :: TransMonad m => m EventF -- | find the first computation state which match a filter in the subthree -- of states findState :: (MonadIO m, Alternative m) => (EventF -> m Bool) -> EventF -> m EventF -- | Return the state variable of the type desired for a thread number getStateFromThread :: (Typeable a, MonadIO m, Alternative m) => String -> EventF -> m (Maybe a) -- | execute all the states of the type desired that are created by direct -- child threads processStates :: Typeable a => (a -> TransIO ()) -> EventF -> TransIO () -- | Add n threads to the limit of threads. If there is no limit, the limit -- is set. addThreads' :: Int -> TransIO () -- | Ensure that at least n threads are available for the current task set. addThreads :: Int -> TransIO () -- | Disable tracking and therefore the ability to terminate the child -- threads. By default, child threads are terminated automatically when -- the parent thread dies, or they can be terminated using the kill -- primitives. Disabling it may improve performance a bit, however, all -- threads must be well-behaved to exit on their own to avoid a leak. freeThreads :: TransIO a -> TransIO a -- | Enable tracking and therefore the ability to terminate the child -- threads. This is the default but can be used to re-enable tracking if -- it was previously disabled with freeThreads. hookedThreads :: TransIO a -> TransIO a -- | Kill all the child threads of the current thread. killChilds :: TransIO () -- | Kill the current thread and the childs. killBranch :: TransIO () -- | Kill the childs and the thread of an state killBranch' :: EventF -> IO () -- | Same as getSData but with a more conventional interface. If the -- data is found, a Just value is returned. Otherwise, a -- Nothing value is returned. getData :: (TransMonad m, Typeable a) => m (Maybe a) -- | Retrieve a previously stored data item of the given data type from the -- monad state. The data type to retrieve is implicitly determined by the -- data type. If the data item is not found, empty is executed, so the -- alternative computation will be executed, if any. Otherwise, the -- computation will stop. If you want to print an error message or return -- a default value, you can use an Alternative composition. For -- example: -- --
-- getSData <|> error "no data of the type desired" -- getInt = getSData <|> return (0 :: Int) ---- -- The later return either the value set or 0. -- -- It is highly recommended not to use it directly, since his relatively -- complex behaviour may be confusing sometimes. Use instead a -- monomorphic alias like "getInt" defined above. getSData :: Typeable a => TransIO a -- | Same as getSData getState :: Typeable a => TransIO a -- | setData stores a data item in the monad state which can be -- retrieved later using getData or getSData. Stored data -- items are keyed by their data type, and therefore only one item of a -- given type can be stored. A newtype wrapper can be used to distinguish -- two data items of the same type. -- --
-- import Control.Monad.IO.Class (liftIO)
-- import Transient.Base
-- import Data.Typeable
--
-- data Person = Person
-- { name :: String
-- , age :: Int
-- } deriving Typeable
--
-- main = keep $ do
-- setData $ Person Alberto 55
-- Person name age <- getSData
-- liftIO $ print (name, age)
--
setData :: (TransMonad m, Typeable a) => a -> m ()
-- | Accepts a function which takes the current value of the stored data
-- type and returns the modified value. If the function returns
-- Nothing the value is deleted otherwise updated.
modifyData :: (TransMonad m, Typeable a) => (Maybe a -> Maybe a) -> m ()
-- | Either modify according with the first parameter or insert according
-- with the second, depending on if the data exist or not. It returns the
-- old value or the new value accordingly.
--
-- -- runTransient $ do modifyData' (\h -> h ++ " world") "hello new" ; r <- getSData ; liftIO $ putStrLn r -- > "hello new" -- runTransient $ do setData "hello" ; modifyData' (\h -> h ++ " world") "hello new" ; r <- getSData ; liftIO $ putStrLn r -- > "hello world" --modifyData' :: (TransMonad m, Typeable a) => (a -> a) -> a -> m a -- | Same as modifyData modifyState :: (TransMonad m, Typeable a) => (Maybe a -> Maybe a) -> m () -- | Same as setData setState :: (TransMonad m, Typeable a) => a -> m () -- | Delete the data item of the given type from the monad state. delData :: (TransMonad m, Typeable a) => a -> m () -- | Same as delData delState :: (TransMonad m, Typeable a) => a -> m () newtype Ref a Ref :: IORef a -> Ref a -- | Initializes a new mutable reference (similar to STRef in the state -- monad) It is polimorphic. Each type has his own reference It return -- the associated IORef, so it can be updated in the IO monad newRState :: (MonadIO m, TransMonad m, Typeable a) => a -> m (IORef a) -- | mutable state reference that can be updated (similar to STRef in the -- state monad) They are identified by his type. Initialized the first -- time it is set. setRState :: (MonadIO m, TransMonad m, Typeable a) => a -> m () getRData :: (MonadIO m, TransMonad m, Typeable a) => m (Maybe a) getRState :: Typeable a => TransIO a delRState :: (MonadState EventF m, Typeable a) => a -> m () -- | Run an action, if it does not succeed, undo any state changes that may -- have been caused by the action and allow aternative actions to run -- with the original state try :: TransIO a -> TransIO a -- | Executes the computation and reset the state either if it fails or -- not. sandbox :: TransIO a -> TransIO a -- | generates an identifier that is unique within the current program -- execution genGlobalId :: MonadIO m => m Int rglobalId :: IORef Int -- | Generator of identifiers that are unique within the current monadic -- sequence They are not unique in the whole program. genId :: TransMonad m => m Int getPrevId :: TransMonad m => m Int -- | StreamData represents an result in an stream being generated. data StreamData a -- | More to come SMore :: a -> StreamData a -- | This is the last one SLast :: a -> StreamData a -- | No more, we are done SDone :: StreamData a -- | An error occurred SError :: SomeException -> StreamData a -- | A task stream generator that produces an infinite stream of results by -- running an IO computation in a loop, each result may be processed in -- different threads (tasks) depending on the thread limits stablished -- with threads. waitEvents :: IO a -> TransIO a -- | Run an IO computation asynchronously carrying the result of the -- computation in a new thread when it completes. If there are no threads -- available, the async computation and his continuation is executed in -- the same thread before any alternative computation. async :: IO a -> TransIO a -- | Avoid the execution of alternative computations when the computation -- is asynchronous -- --
-- sync (async whatever) <|> liftIO (print "hello") -- never print "hello" --sync :: TransIO a -> TransIO a -- | create task threads faster, but with no thread control: spawn = -- freeThreads . waitEvents spawn :: IO a -> TransIO a -- | An stream generator that run an IO computation periodically at the -- specified time interval. The task carries the result of the -- computation. A new result is generated only if the output of the -- computation is different from the previous one. sample :: Eq a => IO a -> Int -> TransIO a -- | Runs the rest of the computation in a new thread. Returns empty -- to the current thread abduce :: TransIO () -- | fork an independent process. It is equivalent to forkIO. The thread -- created is managed with the thread control primitives of transient fork :: TransIO () -> TransIO () -- | Run an IO action one or more times to generate a stream of tasks. The -- IO action returns a StreamData. When it returns an SMore -- or SLast a new result is returned with the result value. If -- there are threads available, the res of the computation is executed in -- a new thread. If the return value is SMore, the action is run -- again to generate the next result, otherwise task creation stop. -- -- Unless the maximum number of threads (set with threads) has -- been reached, the task is generated in a new thread and the current -- thread returns a void task. parallel :: IO (StreamData b) -> TransIO (StreamData b) -- | Execute the IO action and the continuation loop :: EventF -> IO (StreamData t) -> IO () free :: ThreadId -> EventF -> IO () hangThread :: EventF -> EventF -> IO () -- | kill all the child threads associated with the continuation context killChildren :: MVar [EventF] -> IO () -- | capture a callback handler so that the execution of the current -- computation continues whenever an event occurs. The effect is called -- "de-inversion of control" -- -- The first parameter is a callback setter. The second parameter is a -- value to be returned to the callback; if the callback expects no -- return value it can just be return (). The callback setter -- expects a function taking the eventdata as an argument and -- returning a value; this function is the continuation, which is -- supplied by react. -- -- Callbacks from foreign code can be wrapped into such a handler and -- hooked into the transient monad using react. Every time the -- callback is called it continues the execution on the current transient -- computation. -- --
-- -- do -- event <- react onEvent $ return () -- .... --react :: ((eventdata -> IO response) -> IO ()) -> IO response -> TransIO eventdata -- | listen stdin and triggers a new task every time the input data matches -- the first parameter. The value contained by the task is the matched -- value i.e. the first argument itself. The second parameter is a -- message for the user. The label is displayed in the console when the -- option match. option :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b option1 :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b optionf :: (Typeable b, Show b, Read b, Eq b) => Bool -> b -> String -> TransIO b -- | General asynchronous console input. -- -- inputf input listener after sucessful or not identifier -- prompt default value proc inputf :: (Show a, Read a, Typeable a) => Bool -> String -> String -> Maybe a -> (a -> Bool) -> TransIO a -- | Waits on stdin and return a value when a console input matches the -- predicate specified in the first argument. The second parameter is a -- string to be displayed on the console before waiting. input :: (Typeable a, Read a, Show a) => (a -> Bool) -> String -> TransIO a -- | input with a default value input' :: (Typeable a, Read a, Show a) => Maybe a -> (a -> Bool) -> String -> TransIO a rcb :: IORef [(String, String, String -> IO ())] addConsoleAction :: String -> String -> (String -> IO ()) -> IO () delConsoleAction :: String -> IO () reads1 :: (Typeable a, Read a) => [Char] -> [(a, String)] read1 :: (Typeable a, Read a) => [Char] -> a rprompt :: IORef [Char] inputLoop :: () => IO a rconsumed :: IORef Bool lineprocessmode :: IORef Bool processLine :: [Char] -> IO () breakSlash :: [String] -> String -> [String] tail1 :: () => [a] -> [a] -- | Wait for the execution of exit and return the result or the -- exhaustion of thread activity stay :: () => MVar (Maybe a) -> IO (Maybe a) newtype Exit a Exit :: a -> Exit a -- | Runs the transient computation in a child thread and keeps the main -- thread running until all the user threads exit or some thread -- exit. -- -- The main thread provides facilities for accepting keyboard input in a -- non-blocking but line-oriented manner. The program reads the standard -- input and feeds it to all the async input consumers (e.g. -- option and input). All async input consumers contend for -- each line entered on the standard input and try to read it atomically. -- When a consumer consumes the input others do not get to see it, -- otherwise it is left in the buffer for others to consume. If nobody -- consumes the input, it is discarded. -- -- A / in the input line is treated as a newline. -- -- When using asynchronous input, regular synchronous IO APIs like -- getLine cannot be used as they will contend for the standard input -- along with the asynchronous input thread. Instead you can use the -- asynchronous input APIs provided by transient. -- -- A built-in interactive command handler also reads the stdin -- asynchronously. All available options waiting for input are displayed -- when the program is run. The following commands are available: -- --
-- foo -p ps/end --keep :: Typeable a => TransIO a -> IO (Maybe a) -- | Same as keep but does not read from the standard input, and -- therefore the async input APIs (option and input) cannot -- respond interactively. However, input can still be passed via command -- line arguments as described in keep. Useful for debugging or -- for creating background tasks, as well as to embed the Transient monad -- inside another computation. It returns either the value returned by -- exit or Nothing, when there are no more threads running keep' :: Typeable a => TransIO a -> IO (Maybe a) execCommandLine :: IO () -- | Exit the main thread with a result, and thus all the Transient threads -- (and the application if there is no more code) exit :: Typeable a => a -> TransIO a -- | If the first parameter is Nothing return the second parameter -- otherwise return the first parameter.. onNothing :: Monad m => m (Maybe b) -> m b -> m b data Backtrack b Backtrack :: Maybe b -> [EventF] -> Backtrack b [backtracking] :: Backtrack b -> Maybe b [backStack] :: Backtrack b -> [EventF] -- | Delete all the undo actions registered till now for the given track -- id. backCut :: (Typeable b, Show b) => b -> TransientIO () -- | backCut for the default track; equivalent to backCut -- (). undoCut :: TransientIO () -- | Run the action in the first parameter and register the second -- parameter as the undo action. On undo (back) the second -- parameter is called with the undo track id as argument. onBack :: (Typeable b, Show b) => TransientIO a -> (b -> TransientIO a) -> TransientIO a -- | onBack for the default track; equivalent to onBack (). onUndo :: TransientIO a -> TransientIO a -> TransientIO a -- | Register an undo action to be executed when backtracking. The first -- parameter is a "witness" whose data type is used to uniquely identify -- this backtracking action. The value of the witness parameter is not -- used. registerBack :: (Typeable b, Show b) => b -> TransientIO a -> TransientIO a registerUndo :: TransientIO a -> TransientIO a -- | For a given undo track type, stop executing more backtracking actions -- and resume normal execution in the forward direction. Used inside an -- undo action. forward :: (Typeable b, Show b) => b -> TransIO () -- | put at the end of an backtrack handler intended to backtrack to other -- previous handlers. This is the default behaviour in transient. -- backtrack is in order to keep the type compiler happy backtrack :: TransIO a -- | forward for the default undo track; equivalent to forward -- (). retry :: TransIO () -- | Abort finish. Stop executing more finish actions and resume normal -- execution. Used inside onFinish actions. noFinish :: TransIO () -- | Start the undo process for a given undo track identifier type. -- Performs all the undo actions registered for that type in reverse -- order. An undo action can use forward to stop the undo process -- and resume forward execution. If there are no more undo actions -- registered, execution stop back :: (Typeable b, Show b) => b -> TransIO a backStateOf :: (Show a, Typeable a) => a -> Backtrack a data BackPoint a BackPoint :: IORef [a -> TransIO ()] -> BackPoint a -- | a backpoint is a location in the code where callbacks can be installed -- and will be called when the backtracing pass trough that point. -- Normally used for exceptions. backPoint :: (Typeable reason, Show reason) => TransIO (BackPoint reason) -- | install a callback in a backPoint onBackPoint :: MonadIO m => BackPoint t -> (t -> TransIO ()) -> m () -- | back for the default undo track; equivalent to back -- (). undo :: TransIO a newtype Finish Finish :: String -> Finish -- | Clear all finish actions registered till now. initFinish= backCut -- (FinishReason Nothing) -- -- Register an action that to be run when finish is called. -- onFinish can be used multiple times to register multiple -- actions. Actions are run in reverse order. Used in infix style. onFinish :: (Finish -> TransIO ()) -> TransIO () -- | Run the action specified in the first parameter and register the -- second parameter as a finish action to be run when finish is -- called. Used in infix style. onFinish' :: TransIO a -> (Finish -> TransIO a) -> TransIO a -- | Execute all the finalization actions registered up to the last -- initFinish, in reverse order and continue the execution. Either -- an exception or Nothing can be initFinish :: TransIO () finish :: String -> TransIO () -- | trigger finish when the stream of data ends checkFinalize :: () => StreamData a -> TransIO a -- | Install an exception handler. Handlers are executed in reverse (i.e. -- last in, first out) order when such exception happens in the -- continuation. Note that multiple handlers can be installed for the -- same exception type. -- -- The semantic is, thus, very different than the one of -- onException onException :: Exception e => (e -> TransIO ()) -> TransIO () -- | set an exception point. Thi is a point in the backtracking in which -- exception handlers can be inserted with onExceptionPoint it is -- an specialization of backPoint for exceptions. -- -- When an exception backtracking reach the backPoint it executes all the -- handlers registered for it. -- -- Use case: suppose that when a connection fails, you need to stop a -- process. This process may not be started before the connection. -- Perhaps it was initiated after the socket read so an exception will -- not backtrack trough the process, since it is downstream, not -- upstream. The process may be even unrelated to the connection, in -- other branch of the computation. -- -- in this case you only need to create a exceptionPoint before -- stablishin the connection, and use onExceptionPoint to set a -- handler that will be called when the connection fail. exceptionPoint :: Exception e => TransIO (BackPoint e) -- | in conjunction with backPoint it set a handler that will be -- called when backtracking pass trough the point onExceptionPoint :: Exception e => BackPoint e -> (e -> TransIO ()) -> TransIO () onException' :: Exception e => TransIO a -> (e -> TransIO a) -> TransIO a exceptBack :: () => EventF -> SomeException -> IO (Maybe a, EventF) whileException :: Exception e => TransIO b -> (e -> TransIO ()) -> TransIO b -- | Delete all the exception handlers registered till now. cutExceptions :: TransIO () -- | Use it inside an exception handler. it stop executing any further -- exception handlers and resume normal execution from this point on. continue :: TransIO () -- | catch an exception in a Transient block -- -- The semantic is the same than catch but the computation and the -- exception handler can be multirhreaded catcht :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b -- | catch an exception in a Transient block -- -- The semantic is the same than catch but the computation and the -- exception handler can be multirhreaded catcht' :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b -- | throw an exception in the Transient monad there is a difference -- between throw and throwt since the latter preserves the -- state, while the former does not. Any exception not thrown with -- throwt does not preserve the state. -- --
-- main= keep $ do -- onException $ \(e:: SomeException) -> do -- v <- getState <|> return "hello" -- liftIO $ print v -- setState "world" -- throw $ ErrorCall "asdasd" ---- -- the latter print "hello". If you use throwt instead, it prints -- "world" throwt :: Exception e => e -> TransIO a instance GHC.Show.Show Transient.Internals.Finish instance GHC.Read.Read a => GHC.Read.Read (Transient.Internals.StreamData a) instance GHC.Show.Show a => GHC.Show.Show (Transient.Internals.StreamData a) instance GHC.Show.Show Transient.Internals.ExecMode instance GHC.Classes.Eq Transient.Internals.ExecMode instance GHC.Show.Show Transient.Internals.LifeCycle instance GHC.Classes.Eq Transient.Internals.LifeCycle instance GHC.Exception.Type.Exception Transient.Internals.Finish instance Control.Monad.State.Class.MonadState Transient.Internals.EventF m => Transient.Internals.TransMonad m instance Control.Monad.State.Class.MonadState Transient.Internals.EventF Transient.Internals.TransIO instance GHC.Base.Functor Transient.Internals.TransIO instance GHC.Base.Applicative Transient.Internals.TransIO instance GHC.Base.Monad Transient.Internals.TransIO instance Control.Monad.IO.Class.MonadIO Transient.Internals.TransIO instance GHC.Base.Monoid a => GHC.Base.Monoid (Transient.Internals.TransIO a) instance GHC.Base.Monoid a => GHC.Base.Semigroup (Transient.Internals.TransIO a) instance GHC.Base.Alternative Transient.Internals.TransIO instance GHC.Base.MonadPlus Transient.Internals.TransIO instance Control.Monad.Fail.MonadFail Transient.Internals.TransIO instance (GHC.Num.Num a, GHC.Classes.Eq a, GHC.Real.Fractional a) => GHC.Real.Fractional (Transient.Internals.TransIO a) instance (GHC.Num.Num a, GHC.Classes.Eq a) => GHC.Num.Num (Transient.Internals.TransIO a) instance Transient.Internals.AdditionalOperators Transient.Internals.TransIO instance GHC.Base.Functor Transient.Internals.StreamData instance GHC.Show.Show Transient.Internals.ParseError instance GHC.Exception.Type.Exception Transient.Internals.ParseError instance GHC.Read.Read GHC.Exception.Type.SomeException -- | see -- https://www.fpcomplete.com/user/agocorona/beautiful-parallel-non-determinism-transient-effects-iii module Transient.Indeterminism -- | Converts a list of pure values into a transient task set. You can use -- the threads primitive to control the parallelism. choose :: [a] -> TransIO a -- | Same as choose, slower in some cases choose' :: [a] -> TransIO a -- | transmit the end of stream chooseStream :: [a] -> TransIO (StreamData a) -- | Collect the results of the first n tasks. Synchronizes -- concurrent tasks to collect the results safely and kills all the -- non-free threads before returning the results. Results are returned in -- the thread where collect is called. collect :: Int -> TransIO a -> TransIO [a] -- | Like collect but with a timeout. When the timeout is zero it -- behaves exactly like collect. If the timeout (second parameter) -- is non-zero, collection stops after the timeout and the results -- collected till now are returned. collect' :: Int -> Int -> TransIO a -> TransIO [a] -- | Collect the results of a task set in groups of n elements. group :: Int -> TransIO a -> TransIO [a] -- | Collect the results of a task set, grouping all results received -- within every time interval specified by the first parameter as -- diffUTCTime. groupByTime :: Monoid a => Int -> TransIO a -> TransIO a -- | insert SDone response every time there is a timeout since the -- last response burst :: Int -> TransIO a -> TransIO (StreamData a) module Transient.EVars data EVar a EVar :: TChan (StreamData a) -> EVar a -- | creates an EVar. -- -- Evars are event vars. writeEVar trigger the execution of all -- the continuations associated to the readEVar of this variable -- (the code that is after them). -- -- It is like the publish-subscribe pattern but without inversion of -- control, since a readEVar can be inserted at any place in the -- Transient flow. -- -- EVars are created upstream and can be used to communicate two -- sub-threads of the monad. Following the Transient philosophy they do -- not block his own thread if used with alternative operators, unlike -- the IORefs and TVars. And unlike STM vars, that are composable, they -- wait for their respective events, while TVars execute the whole -- expression when any variable is modified. -- -- The execution continues after the writeEVar when all subscribers have -- been executed. -- -- Now the continuations are executed in parallel. -- -- see -- https://www.fpcomplete.com/user/agocorona/publish-subscribe-variables-transient-effects-v newEVar :: TransIO (EVar a) -- | delete al the subscriptions for an evar. cleanEVar :: EVar a -> TransIO () -- | read the EVar. It only succeed when the EVar is being updated The -- continuation gets registered to be executed whenever the variable is -- updated. -- -- if readEVar is re-executed in any kind of loop, since each -- continuation is different, this will register again. The effect is -- that the continuation will be executed multiple times To avoid -- multiple registrations, use cleanEVar readEVar :: EVar a -> TransIO a -- | update the EVar and execute all readEVar blocks with "last in-first -- out" priority writeEVar :: EVar a -> a -> TransIO () -- | write the EVar and drop all the readEVar handlers. -- -- It is like a combination of writeEVar and cleanEVar lastWriteEVar :: MonadIO m => EVar a -> a -> m () -- | Transient implements an event handling mechanism ("backtracking") -- which allows registration of one or more event handlers to be executed -- when an event occurs. This common underlying mechanism called is used -- to handle three different types of events: -- --
-- import Transient.Base (keep, setState, getState) -- import Transient.Backtrack (onUndo, undo) -- import Control.Monad.IO.Class (liftIO) -- -- main = keep $ do -- setState "hello" -- oldState <- getState -- -- liftIO (putStrLn "Register undo") `onUndo` (do -- curState <- getState -- liftIO $ putStrLn $ "Final state: " ++ curState -- liftIO $ putStrLn $ "Old state: " ++ oldState) -- -- setState "world" >> undo >> return () ---- -- See this blog post for more details. module Transient.Backtrack -- | Run the action in the first parameter and register the second -- parameter as the undo action. On undo (back) the second -- parameter is called with the undo track id as argument. onBack :: (Typeable b, Show b) => TransientIO a -> (b -> TransientIO a) -> TransientIO a -- | Start the undo process for a given undo track identifier type. -- Performs all the undo actions registered for that type in reverse -- order. An undo action can use forward to stop the undo process -- and resume forward execution. If there are no more undo actions -- registered, execution stop back :: (Typeable b, Show b) => b -> TransIO a -- | For a given undo track type, stop executing more backtracking actions -- and resume normal execution in the forward direction. Used inside an -- undo action. forward :: (Typeable b, Show b) => b -> TransIO () -- | Delete all the undo actions registered till now for the given track -- id. backCut :: (Typeable b, Show b) => b -> TransientIO () -- | onBack for the default track; equivalent to onBack (). onUndo :: TransientIO a -> TransientIO a -> TransientIO a -- | back for the default undo track; equivalent to back -- (). undo :: TransIO a -- | forward for the default undo track; equivalent to forward -- (). retry :: TransIO () -- | backCut for the default track; equivalent to backCut -- (). undoCut :: TransientIO () -- | Clear all finish actions registered till now. initFinish= backCut -- (FinishReason Nothing) -- -- Register an action that to be run when finish is called. -- onFinish can be used multiple times to register multiple -- actions. Actions are run in reverse order. Used in infix style. onFinish :: (Finish -> TransIO ()) -> TransIO () -- | Run the action specified in the first parameter and register the -- second parameter as a finish action to be run when finish is -- called. Used in infix style. onFinish' :: TransIO a -> (Finish -> TransIO a) -> TransIO a finish :: String -> TransIO () -- | Abort finish. Stop executing more finish actions and resume normal -- execution. Used inside onFinish actions. noFinish :: TransIO () -- | Execute all the finalization actions registered up to the last -- initFinish, in reverse order and continue the execution. Either -- an exception or Nothing can be initFinish :: TransIO () module Transient.Mailboxes mailboxes :: IORef (Map MailboxId (EVar SData)) data MailboxId MailboxId :: a -> TypeRep -> MailboxId -- | write to the mailbox Mailboxes are node-wide, for all processes that -- share the same connection data, that is, are under the same -- listen or connect while EVars are only visible by -- the process that initialized it and his children. Internally, the -- mailbox is in a well known EVar stored by listen in the -- Connection state. putMailbox :: Typeable val => val -> TransIO () -- | write to a mailbox identified by an identifier besides the type putMailbox' :: (Typeable key, Ord key, Typeable val) => key -> val -> TransIO () newMailbox :: MailboxId -> TransIO () -- | get messages from the mailbox that matches with the type expected. The -- order of reading is defined by readTChan This is reactive. it -- means that each new message trigger the execution of the continuation -- each message wake up all the getMailbox computations waiting -- for it. getMailbox :: Typeable val => TransIO val -- | read from a mailbox identified by an identifier besides the type getMailbox' :: (Typeable key, Ord key, Typeable val) => key -> TransIO val -- | delete all subscriptions for that mailbox expecting this kind of data deleteMailbox :: Typeable a => a -> TransIO () -- | clean a mailbox identified by an Int and the type deleteMailbox' :: (Typeable key, Ord key, Typeable a) => key -> a -> TransIO () instance GHC.Classes.Eq Transient.Mailboxes.MailboxId instance GHC.Classes.Ord Transient.Mailboxes.MailboxId instance GHC.Show.Show Transient.Mailboxes.MailboxId module Transient.Parse -- | set a stream of strings to be parsed setParseStream :: TransMonad m => TransIO (StreamData ByteString) -> m () -- | set a string to be parsed setParseString :: TransMonad m => ByteString -> m () withParseString :: ByteString -> TransIO a -> TransIO a withParseStream :: MonadState EventF m => TransIO (StreamData ByteString) -> m b -> m b -- | The parse context contains either the string to be parsed or a -- computation that gives an stream of strings or both. First, the string -- is parsed. If it is empty, the stream is pulled for more. data -- ParseContext str = IsString str => ParseContext (IO (StreamData -- str)) str deriving Typeable -- -- succeed if read the string given as parameter string :: ByteString -> TransIO ByteString -- | fast search for a token. If the token is not found, the parse is left -- in the original state. tDropUntilToken :: ByteString -> TransIO () tTakeUntilToken :: ByteString -> TransIO ByteString -- | read an Integer integer :: TransIO Integer -- | parse an hexadecimal number hex :: TransIO Int -- | read an Int int :: TransIO Int -- | read a double in floating point/scientific notation double :: TransIO Double -- | verify that the next character is the one expected tChar :: Char -> TransIO Char -- | read a char. If there is no input left it fails with empty anyChar :: TransIO Char -- | read many results with a parser (at least one) until a end -- parser succeed. manyTill :: TransIO a -> TransIO b -> TransIO [a] chainManyTill :: Monoid t1 => (t2 -> t1 -> t1) -> TransIO t2 -> TransIO a -> TransIO t1 between :: Monad m => m a1 -> m a2 -> m b -> m b symbol :: ByteString -> TransIO ByteString parens :: () => TransIO b -> TransIO b braces :: () => TransIO b -> TransIO b angles :: () => TransIO b -> TransIO b brackets :: () => TransIO b -> TransIO b semi :: TransIO ByteString comma :: TransIO ByteString dot :: TransIO ByteString colon :: TransIO ByteString sepBy :: () => TransIO a -> TransIO x -> TransIO [a] sepBy1 :: () => TransIO a -> TransIO x -> TransIO [a] chainSepBy :: (Alternative f, Monad f, Monoid a1) => (a2 -> a1 -> a1) -> f a2 -> f x -> f a1 chainSepBy1 :: (Monad m, Monoid b, Alternative m) => (a -> b -> b) -> m a -> m x -> m b chainMany :: (Alternative f, Monad f, Monoid a1) => (a2 -> a1 -> a1) -> f a2 -> f a1 commaSep :: () => TransIO a -> TransIO [a] semiSep :: () => TransIO a -> TransIO [a] commaSep1 :: () => TransIO a -> TransIO [a] dropSpaces :: TransIO () dropTillEndOfLine :: TransIO () parseString :: TransIO ByteString -- | take characters while they meet the condition. if no char matches, it -- returns empty tTakeWhile :: (Char -> Bool) -> TransIO ByteString -- | take from the stream until a condition is met tTakeUntil :: (ByteString -> Bool) -> TransIO ByteString -- | take characters while they meet the condition and drop the next -- character tTakeWhile' :: (Char -> Bool) -> TransIO ByteString -- | take n characters tTake :: Int64 -> TransIO ByteString -- | drop n characters tDrop :: Int64 -> TransIO () -- | drop from the stream until a condition is met tDropUntil :: (ByteString -> Bool) -> TransIO () -- | add the String at the beginning of the stream to be parsed tPutStr :: ByteString -> TransIO () -- | True if the stream has finished isDone :: TransIO Bool dropUntilDone :: TransIO () -- | bring the lazy byteString state to a parser which return the rest of -- the stream together with the result and actualize the byteString state -- with it The tuple that the parser returns should be : (what it -- returns, what should remain to be parsed) withGetParseString :: (ByteString -> TransIO (a, ByteString)) -> TransIO a -- | bring the data of the parse context as a lazy byteString giveParseString :: TransIO ByteString -- | return the portion of the string not parsed it is useful for testing -- purposes: -- --
-- result <- myParser <|> (do rest <- notParsed ; liftIO (print "not parsed this:"++ rest)) ---- -- would print where myParser stopped working. This does not work with -- (infinite) streams. Use getParseBuffer instead notParsed :: TransIO ByteString -- | get the current buffer already read but not yet parsed getParseBuffer :: TransIO ByteString -- | empty the buffer clearParseBuffer :: TransIO () -- | Used for debugging. It shows the next N characters in the parse buffer showNext :: Show a => a -> Int64 -> TransIO () -- | Chain two parsers. The motivation is to parse a chunked HTTP response -- which contains JSON messages. -- -- If the REST response is infinite and contains JSON messages, I have to -- chain the dechunk parser with the JSON decoder of aeson, to produce a -- stream of aeson messages. Since the boundaries of chunks and JSON -- messages do not match, it is not possible to add a decode to -- the monadic pipeline. Since the stream is potentially infinite and/or -- the messages may arrive at any time, I can not wait until all the -- input finish before decoding the messages. -- -- I need to generate a ByteString stream with the first parser, which is -- the input for the second parser. -- -- The first parser wait until the second consume the previous chunk, so -- it is pull-based. -- -- many parsing stages can be chained with this operator. -- -- The output is nondeterministic: it can return 0, 1 or more results -- -- example: https://t.co/fmx1uE2SUd (|--) :: TransIO (StreamData -- BS.ByteString) -> TransIO b -> TransIO b p |-- q = do -- --addThreads 1 v liftIO $ newIORef undefined -- :: TransIO (MVar -- (StreamData BS.ByteString - IO ())) initq v | initp v -- -- catcht (_ :: BlockedIndefinitelyOnMVar) -> empty -- TODO #2 -- use react instrad of MVar's? need buffering-contention where initq v= -- do --abduce r <-withParseStream (takev v ) q liftIO $ print "AFGRT -- WITH" return r (|-) :: TransIO (StreamData ByteString) -> TransIO b -> TransIO b -- | The logged primitive is used to save the results of the -- subcomputations of a transient computation (including all its threads) -- in a log buffer. At any point, a suspend or checkpoint -- can be used to save the accumulated log on a persistent storage. A -- restore reads the saved logs and resumes the computation from -- the saved checkpoint. On resumption, the saved results are used for -- the computations which have already been performed. The log contains -- purely application level state, and is therefore independent of the -- underlying machine architecture. The saved logs can be sent across the -- wire to another machine and the computation can then be resumed on -- that machine. We can also save the log to gather diagnostic -- information. -- -- The following example illustrates the APIs. In its first run -- suspend saves the state in a directory named logs and -- exits, in the second run it resumes from that point and then stops at -- the checkpoint, in the third run it resumes from the checkpoint -- and then finishes. -- --
-- main= keep $ restore $ do
-- r <- logged $ choose [1..10 :: Int]
-- logged $ liftIO $ print ("A",r)
-- suspend ()
-- logged $ liftIO $ print ("B",r)
-- checkpoint
-- liftIO $ print ("C",r)
--
module Transient.Logged
class (Show a, Read a, Typeable a) => Loggable a
serialize :: Loggable a => a -> Builder
deserializePure :: Loggable a => ByteString -> Maybe (a, ByteString)
deserialize :: Loggable a => TransIO a
-- | Run the computation, write its result in a log in the state and return
-- the result. If the log already contains the result of this computation
-- (restored from previous saved state) then that result is used
-- instead of running the computation again.
--
-- logged can be used for computations inside a nother
-- logged computation. Once the parent computation is finished its
-- internal (subcomputation) logs are discarded.
logged :: Loggable a => TransIO a -> TransIO a
received :: (Loggable a, Eq a) => a -> TransIO ()
param :: (Loggable a, Typeable a) => TransIO a
getLog :: TransMonad m => m Log
exec :: Builder
wait :: Builder
emptyLog :: Log
-- | Saves the logged state of the current computation that has been
-- accumulated using logged, and then exits using the
-- passed parameter as the exit code. Note that all the computations
-- before a suspend must be logged to have a consistent log
-- state. The logs are saved in the logs subdirectory of the
-- current directory. Each thread's log is saved in a separate file.
suspend :: Typeable a => a -> TransIO a
-- | Saves the accumulated logs of the current computation, like
-- suspend, but does not exit.
checkpoint :: TransIO ()
-- | Reads the saved logs from the logs subdirectory of the
-- current directory, restores the state of the computation from the
-- logs, and runs the computation. The log files are maintained. It could
-- be used for the initial configuration of a program.
rerun :: String -> TransIO a -> TransIO a
-- | Reads the saved logs from the logs subdirectory of the
-- current directory, restores the state of the computation from the
-- logs, and runs the computation. The log files are removed after the
-- state has been restored.
restore :: TransIO a -> TransIO a
data Log
Log :: Bool -> Builder -> Builder -> Int -> Int -> Log
[recover] :: Log -> Bool
[buildLog] :: Log -> Builder
[fulLog] :: Log -> Builder
[lengthFull] :: Log -> Int
[hashClosure] :: Log -> Int
-- | Execute a Builder and return the generated chunks as a lazy
-- ByteString. The work is performed lazy, i.e., only when a chunk
-- of the lazy ByteString is forced.
toLazyByteString :: Builder -> ByteString
-- | Create a Builder denoting the same sequence of bytes as a
-- strict ByteString. The Builder inserts large
-- ByteStrings directly, but copies small ones to ensure that the
-- generated chunks are large on average.
byteString :: ByteString -> Builder
-- | Create a Builder denoting the same sequence of bytes as a lazy
-- ByteString. The Builder inserts large chunks of the lazy
-- ByteString directly, but copies small ones to ensure that the
-- generated chunks are large on average.
lazyByteString :: ByteString -> Builder
newtype Raw
Raw :: ByteString -> Raw
instance GHC.Show.Show Transient.Logged.Raw
instance GHC.Read.Read Transient.Logged.Raw
instance Transient.Logged.Loggable Transient.Logged.Raw
instance Transient.Logged.Loggable ()
instance Transient.Logged.Loggable GHC.Types.Bool
instance Transient.Logged.Loggable GHC.Types.Int
instance Transient.Logged.Loggable GHC.Integer.Type.Integer
instance (Data.Typeable.Internal.Typeable a, Transient.Logged.Loggable a) => Transient.Logged.Loggable [a]
instance Transient.Logged.Loggable GHC.Types.Char
instance Transient.Logged.Loggable GHC.Types.Float
instance Transient.Logged.Loggable GHC.Types.Double
instance Transient.Logged.Loggable a => Transient.Logged.Loggable (GHC.Maybe.Maybe a)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b) => Transient.Logged.Loggable (a, b)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c) => Transient.Logged.Loggable (a, b, c)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d) => Transient.Logged.Loggable (a, b, c, d)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d, Transient.Logged.Loggable e) => Transient.Logged.Loggable (a, b, c, d, e)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d, Transient.Logged.Loggable e, Transient.Logged.Loggable f) => Transient.Logged.Loggable (a, b, c, d, e, f)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d, Transient.Logged.Loggable e, Transient.Logged.Loggable f, Transient.Logged.Loggable g) => Transient.Logged.Loggable (a, b, c, d, e, f, g)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d, Transient.Logged.Loggable e, Transient.Logged.Loggable f, Transient.Logged.Loggable g, Transient.Logged.Loggable h) => Transient.Logged.Loggable (a, b, c, d, e, f, g, h)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b, Transient.Logged.Loggable c, Transient.Logged.Loggable d, Transient.Logged.Loggable e, Transient.Logged.Loggable f, Transient.Logged.Loggable g, Transient.Logged.Loggable h, Transient.Logged.Loggable i) => Transient.Logged.Loggable (a, b, c, d, e, f, g, h, i)
instance (Transient.Logged.Loggable a, Transient.Logged.Loggable b) => Transient.Logged.Loggable (Data.Either.Either a b)
instance (Transient.Logged.Loggable k, GHC.Classes.Ord k, Transient.Logged.Loggable a) => Transient.Logged.Loggable (Data.Map.Internal.Map k a)
instance Transient.Logged.Loggable Data.ByteString.Lazy.Internal.ByteString
instance Transient.Logged.Loggable Data.ByteString.Internal.ByteString
instance Transient.Logged.Loggable GHC.Exception.Type.SomeException
-- | Transient provides high level concurrency allowing you to do
-- concurrent processing without requiring any knowledge of threads or
-- synchronization. From the programmer's perspective, the programming
-- model is single threaded. Concurrent tasks are created and composed
-- seamlessly resulting in highly modular and composable concurrent
-- programs. Transient has diverse applications from simple concurrent
-- applications to massively parallel and distributed map-reduce
-- problems. If you are considering Apache Spark or Cloud Haskell then
-- transient might be a simpler yet better solution for you (see
-- transient-universe). Transient makes it easy to write
-- composable event driven reactive UI applications. For example,
-- Axiom is a transient based unified client and server side
-- framework that provides a better programming model and composability
-- compared to frameworks like ReactJS.
--
-- -- import Control.Concurrent (threadDelay) -- import Control.Monad.IO.Class (liftIO) -- import System.Random (randomIO) -- import Transient.Base (keep, threads, waitEvents) -- -- main = keep $ threads 0 $ do -- x <- waitEvents (randomIO :: IO Int) -- liftIO $ threadDelay 1000000 -- liftIO $ putStrLn $ show x ---- -- keep runs the TransientIO monad. The threads -- primitive limits the number of threads to force non-concurrent -- operation. The waitEvents primitive generates values (list -- elements) in a loop using the randomIO IO action. The above -- code behaves like a list monad as if we are drawing elements from a -- list generated by waitEvents. The sequence of actions following -- waitEvents is executed for each element of the list. We see a -- random value printed on the screen every second. As you can see this -- behavior is identical to a list transformer monad. -- --
-- ... -- main = keep $ threads 10 $ do -- ... ---- -- Now each element of the list is processed concurrently in a separate -- thread, up to 10 threads are used. Therefore we see 10 results printed -- every second instead of 1 in the previous version. -- -- In the above examples the list elements are generated using a -- synchronous IO action. These elements can also be asynchronous events, -- for example an interactive user input. In transient, the elements of -- the list are known as tasks. The tasks terminology is general and -- intuitive in the context of transient as tasks can be triggered by -- asynchronous events and multiple of them can run simultaneously in an -- unordered fashion. -- --
-- main = keep $ threads 0 $ do -- x <- waitEvents (randomIO :: IO Int) -- liftIO $ threadDelay 1000000 -- liftIO $ putStrLn $ "stop here" -- stop -- liftIO $ putStrLn $ show x ---- -- When a task creation primitive creates a task concurrently in a new -- thread (e.g. waitEvents), it returns a void task set in the -- current thread making it stop further processing. However, processing -- resumes from the same point onwards with the same state in the new -- task threads as and when they are created; as if the current thread -- along with its state has branched into multiple threads, one for each -- new task. In the following example you can see that the thread id -- changes after the waitEvents call: -- --
-- main = keep $ threads 1 $ do -- mainThread <- liftIO myThreadId -- liftIO $ putStrLn $ "Main thread: " ++ show mainThread -- x <- waitEvents (randomIO :: IO Int) -- -- liftIO $ threadDelay 1000000 -- evThread <- liftIO myThreadId -- liftIO $ putStrLn $ "Event thread: " ++ show evThread ---- -- Note that if we use threads 0 then the new task thread is the -- same as the main thread because waitEvents falls back to -- synchronous non-concurrent mode, and therefore returns a non void task -- set. -- -- In an Alternative composition, when a computation results in -- empty the next alternative is tried. When a task creation -- primitive creates a concurrent task, it returns empty -- allowing tasks to run concurrently when composed with the -- <|> combinator. The following example combines two -- single concurrent tasks generated by async: -- --
-- main = keep $ do -- x <- event 1 <|> event 2 -- liftIO $ putStrLn $ show x -- where event n = async (return n :: IO Int) ---- -- Note that availability of threads can impact the behavior of an -- application. An infinite task set generator (e.g. waitEvents or -- sample) running synchronously (due to lack of threads) can -- block all other computations in an Alternative composition. -- The following example does not trigger the async task unless we -- increase the number of threads to make waitEvents asynchronous: -- --
-- main = keep $ threads 0 $ do -- x <- waitEvents (randomIO :: IO Int) <|> async (return 0 :: IO Int) -- liftIO $ threadDelay 1000000 -- liftIO $ putStrLn $ show x ---- --
-- import Control.Monad.IO.Class (liftIO) -- import Data.List (sum) -- import Transient.Base (keep) -- import Transient.Indeterminism (choose, collect) -- -- main = keep $ do -- collect 100 squares >>= liftIO . putStrLn . show . sum -- where -- squares = do -- x <- choose [1..100] -- return (x * x) ---- --
-- foo -p ps/end --keep :: Typeable a => TransIO a -> IO (Maybe a) -- | Same as keep but does not read from the standard input, and -- therefore the async input APIs (option and input) cannot -- respond interactively. However, input can still be passed via command -- line arguments as described in keep. Useful for debugging or -- for creating background tasks, as well as to embed the Transient monad -- inside another computation. It returns either the value returned by -- exit or Nothing, when there are no more threads running keep' :: Typeable a => TransIO a -> IO (Maybe a) -- | A synonym of empty that can be used in a monadic expression. It -- stops the computation, which allows the next computation in an -- Alternative (<|>) composition to run. stop :: Alternative m => m stopped -- | Exit the main thread with a result, and thus all the Transient threads -- (and the application if there is no more code) exit :: Typeable a => a -> TransIO a -- | listen stdin and triggers a new task every time the input data matches -- the first parameter. The value contained by the task is the matched -- value i.e. the first argument itself. The second parameter is a -- message for the user. The label is displayed in the console when the -- option match. option :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b option1 :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b -- | Waits on stdin and return a value when a console input matches the -- predicate specified in the first argument. The second parameter is a -- string to be displayed on the console before waiting. input :: (Typeable a, Read a, Show a) => (a -> Bool) -> String -> TransIO a -- | input with a default value input' :: (Typeable a, Read a, Show a) => Maybe a -> (a -> Bool) -> String -> TransIO a -- | StreamData represents an result in an stream being generated. data StreamData a -- | More to come SMore :: a -> StreamData a -- | This is the last one SLast :: a -> StreamData a -- | No more, we are done SDone :: StreamData a -- | An error occurred SError :: SomeException -> StreamData a -- | Run an IO action one or more times to generate a stream of tasks. The -- IO action returns a StreamData. When it returns an SMore -- or SLast a new result is returned with the result value. If -- there are threads available, the res of the computation is executed in -- a new thread. If the return value is SMore, the action is run -- again to generate the next result, otherwise task creation stop. -- -- Unless the maximum number of threads (set with threads) has -- been reached, the task is generated in a new thread and the current -- thread returns a void task. parallel :: IO (StreamData b) -> TransIO (StreamData b) -- | Run an IO computation asynchronously carrying the result of the -- computation in a new thread when it completes. If there are no threads -- available, the async computation and his continuation is executed in -- the same thread before any alternative computation. async :: IO a -> TransIO a -- | A task stream generator that produces an infinite stream of results by -- running an IO computation in a loop, each result may be processed in -- different threads (tasks) depending on the thread limits stablished -- with threads. waitEvents :: IO a -> TransIO a -- | An stream generator that run an IO computation periodically at the -- specified time interval. The task carries the result of the -- computation. A new result is generated only if the output of the -- computation is different from the previous one. sample :: Eq a => IO a -> Int -> TransIO a -- | create task threads faster, but with no thread control: spawn = -- freeThreads . waitEvents spawn :: IO a -> TransIO a -- | capture a callback handler so that the execution of the current -- computation continues whenever an event occurs. The effect is called -- "de-inversion of control" -- -- The first parameter is a callback setter. The second parameter is a -- value to be returned to the callback; if the callback expects no -- return value it can just be return (). The callback setter -- expects a function taking the eventdata as an argument and -- returning a value; this function is the continuation, which is -- supplied by react. -- -- Callbacks from foreign code can be wrapped into such a handler and -- hooked into the transient monad using react. Every time the -- callback is called it continues the execution on the current transient -- computation. -- --
-- -- do -- event <- react onEvent $ return () -- .... --react :: ((eventdata -> IO response) -> IO ()) -> IO response -> TransIO eventdata -- | Runs the rest of the computation in a new thread. Returns empty -- to the current thread abduce :: TransIO () -- | fork an independent process. It is equivalent to forkIO. The thread -- created is managed with the thread control primitives of transient fork :: TransIO () -> TransIO () -- | Avoid the execution of alternative computations when the computation -- is asynchronous -- --
-- sync (async whatever) <|> liftIO (print "hello") -- never print "hello" --sync :: TransIO a -> TransIO a -- | setData stores a data item in the monad state which can be -- retrieved later using getData or getSData. Stored data -- items are keyed by their data type, and therefore only one item of a -- given type can be stored. A newtype wrapper can be used to distinguish -- two data items of the same type. -- --
-- import Control.Monad.IO.Class (liftIO)
-- import Transient.Base
-- import Data.Typeable
--
-- data Person = Person
-- { name :: String
-- , age :: Int
-- } deriving Typeable
--
-- main = keep $ do
-- setData $ Person Alberto 55
-- Person name age <- getSData
-- liftIO $ print (name, age)
--
setData :: (TransMonad m, Typeable a) => a -> m ()
-- | Retrieve a previously stored data item of the given data type from the
-- monad state. The data type to retrieve is implicitly determined by the
-- data type. If the data item is not found, empty is executed, so the
-- alternative computation will be executed, if any. Otherwise, the
-- computation will stop. If you want to print an error message or return
-- a default value, you can use an Alternative composition. For
-- example:
--
-- -- getSData <|> error "no data of the type desired" -- getInt = getSData <|> return (0 :: Int) ---- -- The later return either the value set or 0. -- -- It is highly recommended not to use it directly, since his relatively -- complex behaviour may be confusing sometimes. Use instead a -- monomorphic alias like "getInt" defined above. getSData :: Typeable a => TransIO a -- | Same as getSData but with a more conventional interface. If the -- data is found, a Just value is returned. Otherwise, a -- Nothing value is returned. getData :: (TransMonad m, Typeable a) => m (Maybe a) -- | Delete the data item of the given type from the monad state. delData :: (TransMonad m, Typeable a) => a -> m () -- | Accepts a function which takes the current value of the stored data -- type and returns the modified value. If the function returns -- Nothing the value is deleted otherwise updated. modifyData :: (TransMonad m, Typeable a) => (Maybe a -> Maybe a) -> m () -- | Either modify according with the first parameter or insert according -- with the second, depending on if the data exist or not. It returns the -- old value or the new value accordingly. -- --
-- runTransient $ do modifyData' (\h -> h ++ " world") "hello new" ; r <- getSData ; liftIO $ putStrLn r -- > "hello new" -- runTransient $ do setData "hello" ; modifyData' (\h -> h ++ " world") "hello new" ; r <- getSData ; liftIO $ putStrLn r -- > "hello world" --modifyData' :: (TransMonad m, Typeable a) => (a -> a) -> a -> m a -- | Run an action, if it does not succeed, undo any state changes that may -- have been caused by the action and allow aternative actions to run -- with the original state try :: TransIO a -> TransIO a -- | Same as setData setState :: (TransMonad m, Typeable a) => a -> m () -- | Same as getSData getState :: Typeable a => TransIO a -- | Same as delData delState :: (TransMonad m, Typeable a) => a -> m () -- | Initializes a new mutable reference (similar to STRef in the state -- monad) It is polimorphic. Each type has his own reference It return -- the associated IORef, so it can be updated in the IO monad newRState :: (MonadIO m, TransMonad m, Typeable a) => a -> m (IORef a) getRState :: Typeable a => TransIO a -- | mutable state reference that can be updated (similar to STRef in the -- state monad) They are identified by his type. Initialized the first -- time it is set. setRState :: (MonadIO m, TransMonad m, Typeable a) => a -> m () -- | Same as modifyData modifyState :: (TransMonad m, Typeable a) => (Maybe a -> Maybe a) -> m () -- | Add a label to the current passing threads so it can be printed by -- debugging calls like showThreads labelState :: (MonadIO m, TransMonad m) => ByteString -> m () -- | find the first computation state which match a filter in the subthree -- of states findState :: (MonadIO m, Alternative m) => (EventF -> m Bool) -> EventF -> m EventF -- | kill the thread subtree labeled as such (you can see all of them with -- the console option ps) killState :: (MonadIO m, Alternative m, MonadState EventF m) => ByteString -> m () -- | Sets the maximum number of threads that can be created for the given -- task set. When set to 0, new tasks start synchronously in the current -- thread. New threads are created by parallel, and APIs that use -- parallel. threads :: Int -> TransIO a -> TransIO a -- | Ensure that at least n threads are available for the current task set. addThreads :: Int -> TransIO () -- | Disable tracking and therefore the ability to terminate the child -- threads. By default, child threads are terminated automatically when -- the parent thread dies, or they can be terminated using the kill -- primitives. Disabling it may improve performance a bit, however, all -- threads must be well-behaved to exit on their own to avoid a leak. freeThreads :: TransIO a -> TransIO a -- | Enable tracking and therefore the ability to terminate the child -- threads. This is the default but can be used to re-enable tracking if -- it was previously disabled with freeThreads. hookedThreads :: TransIO a -> TransIO a -- | Terminate all the child threads in the given task set and continue -- execution in the current thread. Useful to reap the children when a -- task is done, restart a task when a new event happens etc. oneThread :: TransIO a -> TransIO a -- | Kill all the child threads of the current thread. killChilds :: TransIO () -- | back for the default undo track; equivalent to back -- (). undo :: TransIO a -- | onBack for the default track; equivalent to onBack (). onUndo :: TransientIO a -> TransientIO a -> TransientIO a -- | forward for the default undo track; equivalent to forward -- (). retry :: TransIO () -- | Start the undo process for a given undo track identifier type. -- Performs all the undo actions registered for that type in reverse -- order. An undo action can use forward to stop the undo process -- and resume forward execution. If there are no more undo actions -- registered, execution stop back :: (Typeable b, Show b) => b -> TransIO a -- | Run the action in the first parameter and register the second -- parameter as the undo action. On undo (back) the second -- parameter is called with the undo track id as argument. onBack :: (Typeable b, Show b) => TransientIO a -> (b -> TransientIO a) -> TransientIO a -- | For a given undo track type, stop executing more backtracking actions -- and resume normal execution in the forward direction. Used inside an -- undo action. forward :: (Typeable b, Show b) => b -> TransIO () -- | a backpoint is a location in the code where callbacks can be installed -- and will be called when the backtracing pass trough that point. -- Normally used for exceptions. backPoint :: (Typeable reason, Show reason) => TransIO (BackPoint reason) -- | install a callback in a backPoint onBackPoint :: MonadIO m => BackPoint t -> (t -> TransIO ()) -> m () finish :: String -> TransIO () -- | Clear all finish actions registered till now. initFinish= backCut -- (FinishReason Nothing) -- -- Register an action that to be run when finish is called. -- onFinish can be used multiple times to register multiple -- actions. Actions are run in reverse order. Used in infix style. onFinish :: (Finish -> TransIO ()) -> TransIO () -- | Install an exception handler. Handlers are executed in reverse (i.e. -- last in, first out) order when such exception happens in the -- continuation. Note that multiple handlers can be installed for the -- same exception type. -- -- The semantic is, thus, very different than the one of -- onException onException :: Exception e => (e -> TransIO ()) -> TransIO () onException' :: Exception e => TransIO a -> (e -> TransIO a) -> TransIO a whileException :: Exception e => TransIO b -> (e -> TransIO ()) -> TransIO b -- | Delete all the exception handlers registered till now. cutExceptions :: TransIO () -- | Use it inside an exception handler. it stop executing any further -- exception handlers and resume normal execution from this point on. continue :: TransIO () -- | catch an exception in a Transient block -- -- The semantic is the same than catch but the computation and the -- exception handler can be multirhreaded catcht :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b -- | throw an exception in the Transient monad there is a difference -- between throw and throwt since the latter preserves the -- state, while the former does not. Any exception not thrown with -- throwt does not preserve the state. -- --
-- main= keep $ do -- onException $ \(e:: SomeException) -> do -- v <- getState <|> return "hello" -- liftIO $ print v -- setState "world" -- throw $ ErrorCall "asdasd" ---- -- the latter print "hello". If you use throwt instead, it prints -- "world" throwt :: Exception e => e -> TransIO a -- | set an exception point. Thi is a point in the backtracking in which -- exception handlers can be inserted with onExceptionPoint it is -- an specialization of backPoint for exceptions. -- -- When an exception backtracking reach the backPoint it executes all the -- handlers registered for it. -- -- Use case: suppose that when a connection fails, you need to stop a -- process. This process may not be started before the connection. -- Perhaps it was initiated after the socket read so an exception will -- not backtrack trough the process, since it is downstream, not -- upstream. The process may be even unrelated to the connection, in -- other branch of the computation. -- -- in this case you only need to create a exceptionPoint before -- stablishin the connection, and use onExceptionPoint to set a -- handler that will be called when the connection fail. exceptionPoint :: Exception e => TransIO (BackPoint e) -- | in conjunction with backPoint it set a handler that will be -- called when backtracking pass trough the point onExceptionPoint :: Exception e => BackPoint e -> (e -> TransIO ()) -> TransIO () -- | Generator of identifiers that are unique within the current monadic -- sequence They are not unique in the whole program. genId :: TransMonad m => m Int -- | Execute a Builder and return the generated chunks as a lazy -- ByteString. The work is performed lazy, i.e., only when a chunk -- of the lazy ByteString is forced. toLazyByteString :: Builder -> ByteString -- | Create a Builder denoting the same sequence of bytes as a lazy -- ByteString. The Builder inserts large chunks of the lazy -- ByteString directly, but copies small ones to ensure that the -- generated chunks are large on average. lazyByteString :: ByteString -> Builder -- | Create a Builder denoting the same sequence of bytes as a -- strict ByteString. The Builder inserts large -- ByteStrings directly, but copies small ones to ensure that the -- generated chunks are large on average. byteString :: ByteString -> Builder data Log Log :: Bool -> Builder -> Builder -> Int -> Int -> Log [recover] :: Log -> Bool [buildLog] :: Log -> Builder [fulLog] :: Log -> Builder [lengthFull] :: Log -> Int [hashClosure] :: Log -> Int newtype Raw Raw :: ByteString -> Raw class (Show a, Read a, Typeable a) => Loggable a serialize :: Loggable a => a -> Builder deserializePure :: Loggable a => ByteString -> Maybe (a, ByteString) deserialize :: Loggable a => TransIO a -- | Reads the saved logs from the logs subdirectory of the -- current directory, restores the state of the computation from the -- logs, and runs the computation. The log files are maintained. It could -- be used for the initial configuration of a program. rerun :: String -> TransIO a -> TransIO a -- | Reads the saved logs from the logs subdirectory of the -- current directory, restores the state of the computation from the -- logs, and runs the computation. The log files are removed after the -- state has been restored. restore :: TransIO a -> TransIO a -- | Saves the logged state of the current computation that has been -- accumulated using logged, and then exits using the -- passed parameter as the exit code. Note that all the computations -- before a suspend must be logged to have a consistent log -- state. The logs are saved in the logs subdirectory of the -- current directory. Each thread's log is saved in a separate file. suspend :: Typeable a => a -> TransIO a -- | Saves the accumulated logs of the current computation, like -- suspend, but does not exit. checkpoint :: TransIO () getLog :: TransMonad m => m Log emptyLog :: Log -- | Run the computation, write its result in a log in the state and return -- the result. If the log already contains the result of this computation -- (restored from previous saved state) then that result is used -- instead of running the computation again. -- -- logged can be used for computations inside a nother -- logged computation. Once the parent computation is finished its -- internal (subcomputation) logs are discarded. logged :: Loggable a => TransIO a -> TransIO a received :: (Loggable a, Eq a) => a -> TransIO () param :: (Loggable a, Typeable a) => TransIO a