-- 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.5.6 -- | See http://github.com/agocorona/transient Everything in this -- module is exported in order to allow extensibility. module Transient.Internals (!>) :: a -> b -> a 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) -> EventF [meffects] :: EventF -> () -- | Not yet consumed result (event) from the last asynchronous run of the -- 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) type Effects = forall a b c. TransIO a -> TransIO a -> (a -> TransIO b) -> StateIO (StateIO (Maybe c) -> StateIO (Maybe c), Maybe a) -- | Run a "non transient" computation within the underlying state monad, -- so it is guaranteed that the computation neither can stop neither can -- trigger additional events/threads. noTrans :: StateIO x -> TransIO x 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) -- | 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 :: MonadState EventF 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 readWithErr :: (Typeable a, Read a) => String -> IO [(a, String)] readsPrec' :: (Read a, Typeable * a) => t -> String -> [(a, String)] -- | Constraint type synonym for a value that can be logged. type Loggable a = (Show a, Read a, Typeable a) -- | Dynamic serializable data for logging. data IDynamic IDyns :: String -> IDynamic IDynamic :: a -> IDynamic type Recover = Bool type CurrentPointer = [LogElem] type LogEntries = [LogElem] data LogElem Wait :: LogElem Exec :: LogElem Var :: IDynamic -> LogElem data Log Log :: Recover -> CurrentPointer -> LogEntries -> Log data RemoteStatus WasRemote :: RemoteStatus WasParallel :: RemoteStatus NoRemote :: RemoteStatus -- | 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 where atEnd' = (<**) atEnd = (<***) -- | 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 -- | 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 EventF -- | 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 (TransIO b -> -- TransIO b) resetEventCont :: MonadState EventF m => Maybe t1 -> t -> m (a -> a) -- | Total variant of tail that returns an empty list when given an -- empty list. tailsafe :: [a] -> [a] waitQSemB :: (Num a, Ord a) => 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 -- | 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. 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, MonadState EventF m) => String -> 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 -- | Return the state variable of the type desired with which a thread, -- identified by his number in the treee was initiated showState :: (Typeable a, MonadIO m, Alternative m) => String -> EventF -> m (Maybe a) -- | 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 general type. If the data is -- found, a Just value is returned. Otherwise, a Nothing -- value is returned. getData :: (MonadState EventF 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 from -- the requested type context. If the data item is not found, an -- empty value (a void event) is returned. Remember that an empty -- value stops the monad computation. If you want to print an error -- message or a default value in that case, you can use an -- Alternative composition. For example: -- --
-- getSData <|> error "no data" -- getInt = getSData <|> return (0 :: Int) --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 :: (MonadState EventF m, Typeable a) => a -> m ()
-- | Accepts a function that 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 :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> m ()
-- | Same as modifyData
modifyState :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> m ()
-- | Same as setData
setState :: (MonadState EventF m, Typeable a) => a -> m ()
-- | Delete the data item of the given type from the monad state.
delData :: (MonadState EventF m, Typeable a) => a -> m ()
-- | Same as delData
delState :: (MonadState EventF m, Typeable a) => a -> m ()
-- | Run an action, if the result is a void action undo any state changes
-- that it might have caused.
try :: TransIO a -> TransIO a
-- | Executes the computation and reset the state either if it fails or not
sandbox :: TransIO a -> TransIO a
-- | Generator of identifiers that are unique within the current monadic
-- sequence They are not unique in the whole program.
genId :: MonadState EventF m => m Int
getPrevId :: MonadState EventF m => m Int
-- | StreamData represents a task in a task stream being generated.
data StreamData a
-- | More tasks to come
SMore :: a -> StreamData a
-- | This is the last task
SLast :: a -> StreamData a
-- | No more tasks, we are done
SDone :: StreamData a
-- | An error occurred
SError :: SomeException -> StreamData a
-- | An task stream generator that produces an infinite stream of tasks by
-- running an IO computation in a loop. A task is triggered carrying the
-- output of the computation. See parallel for notes on the return
-- value.
waitEvents :: IO a -> TransIO a
-- | Run an IO computation asynchronously and generate a single task
-- carrying the result of the computation when it completes. See
-- parallel for notes on the return value.
async :: IO a -> TransIO a
-- | Force an async computation to run synchronously. It can be useful in
-- an Alternative composition to run the alternative only after
-- finishing a computation. Note that in Applicatives it might result in
-- an undesired serialization.
sync :: TransIO a -> TransIO a
-- | -- spawn = freeThreads . waitEvents --spawn :: IO a -> TransIO a -- | An task stream generator that produces an infinite stream of tasks by -- running an IO computation periodically at the specified time interval. -- The task carries the result of the computation. A new task is -- generated only if the output of the computation is different from the -- previous one. See parallel for notes on the return value. sample :: Eq a => IO a -> Int -> TransIO 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 task is triggered with the result value. If the -- return value is SMore, the action is run again to generate the -- next task, otherwise task creation stops. -- -- 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 () -- | Make a transient task generator from an asynchronous callback handler. -- -- The first parameter is a callback. The second parameter is a value to -- be returned to the callback; if the callback expects no return value -- it can just be a return (). The callback expects a setter -- function taking the eventdata as an argument and returning a -- value to the callback; this function 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 generates a new task for the transient monad. react :: Typeable eventdata => ((eventdata -> IO response) -> IO ()) -> IO response -> TransIO eventdata -- | Runs a computation asynchronously without generating any events. -- Returns empty in an Alternative composition. abduce :: TransIO () getLineRef :: TVar (Maybe a) roption :: MVar [t] -- | Waits on stdin in a loop 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 label for the option. The label is displayed on the console when -- the option is activated. -- -- Note that if two independent invocations of option are -- expecting the same input, only one of them gets it and triggers a -- task. It cannot be predicted which one gets it. option :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b -- | Waits on stdin and triggers a task 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 :: (Show a, Read a, Typeable * a) => (a -> Bool) -> String -> TransIO a input' :: (Typeable a, Read a, Show a) => Maybe a -> (a -> Bool) -> String -> TransIO a -- | Non blocking getLine with a validator getLine' :: (Read a, Typeable * a) => (a -> Bool) -> IO a reads1 :: (Typeable * a, Read a) => String -> [(a, String)] inputLoop :: IO b processLine :: MonadIO m => String -> m () -- | 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 invokes -- exit. -- -- The main thread provides facilities to accept 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 commands handled by the command handler -- 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 -- be used in the monad. However, keyboard 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, 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 id, 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 () -- | 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 the given undo track id. Performs all the -- undo actions registered till now 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 -- stops and a stop action is returned. back :: (Typeable b, Show b) => b -> TransientIO a backStateOf :: (Monad m, Show a, Typeable a) => a -> m (Backtrack a) -- | back for the default undo track; equivalent to back -- (). undo :: TransIO a newtype FinishReason FinishReason :: (Maybe SomeException) -> FinishReason -- | Clear all finish actions registered till now. initFinish :: TransientIO () -- | 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 :: ((Maybe SomeException) -> 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 -> ((Maybe SomeException) -> TransIO a) -> TransIO a -- | Execute all the finalization actions registered up to the last -- initFinish, in reverse order. Either an exception or -- Nothing can be passed to finish. The argument passed is -- made available in the onFinish actions invoked. finish :: Maybe SomeException -> TransIO a -- | trigger finish when the stream of data ends checkFinalize :: StreamData a -> TransIO a -- | Install an exception handler. On exception, currently installed -- handlers are executed in reverse (i.e. last in first out) order. Note -- that multiple handlers can be installed for the same exception type. onException :: Exception e => (e -> TransIO ()) -> TransIO () onException' :: Exception e => TransIO a -> (e -> TransIO a) -> TransIO a -- | Delete all the exception handlers registered till now. cutExceptions :: TransientIO () -- | Used inside an exception handler. Stop executing any further exception -- handlers and resume normal execution from this point on. continue :: TransIO () catcht :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b throwt :: Exception e => e -> TransIO a instance GHC.Show.Show Transient.Internals.FinishReason 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.RemoteStatus instance GHC.Classes.Eq Transient.Internals.RemoteStatus instance GHC.Show.Show Transient.Internals.Log instance GHC.Show.Show Transient.Internals.LogElem instance GHC.Read.Read Transient.Internals.LogElem instance GHC.Show.Show Transient.Internals.LifeCycle instance GHC.Classes.Eq Transient.Internals.LifeCycle 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.Alternative Transient.Internals.TransIO instance GHC.Base.MonadPlus Transient.Internals.TransIO instance GHC.Show.Show Transient.Internals.IDynamic instance GHC.Read.Read Transient.Internals.IDynamic 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.Read.Read GHC.Exception.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 :: Show a => [a] -> TransIO a -- | Same as choose except that the threads combinator cannot -- be used, instead the parent thread's limit applies. choose' :: [a] -> TransIO 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 :: Integer -> TransIO a -> TransIO [a] -- | 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 -- be used in the monad. However, keyboard 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, and thus all the Transient threads (and the -- application if there is no more code) exit :: Typeable a => a -> TransIO a -- | Waits on stdin in a loop 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 label for the option. The label is displayed on the console when -- the option is activated. -- -- Note that if two independent invocations of option are -- expecting the same input, only one of them gets it and triggers a -- task. It cannot be predicted which one gets it. option :: (Typeable b, Show b, Read b, Eq b) => b -> String -> TransIO b -- | Waits on stdin and triggers a task 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 :: (Show a, Read a, Typeable * a) => (a -> Bool) -> String -> TransIO a input' :: (Typeable a, Read a, Show a) => Maybe a -> (a -> Bool) -> String -> TransIO a -- | StreamData represents a task in a task stream being generated. data StreamData a -- | More tasks to come SMore :: a -> StreamData a -- | This is the last task SLast :: a -> StreamData a -- | No more tasks, 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 task is triggered with the result value. If the -- return value is SMore, the action is run again to generate the -- next task, otherwise task creation stops. -- -- 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 and generate a single task -- carrying the result of the computation when it completes. See -- parallel for notes on the return value. async :: IO a -> TransIO a -- | An task stream generator that produces an infinite stream of tasks by -- running an IO computation in a loop. A task is triggered carrying the -- output of the computation. See parallel for notes on the return -- value. waitEvents :: IO a -> TransIO a -- | An task stream generator that produces an infinite stream of tasks by -- running an IO computation periodically at the specified time interval. -- The task carries the result of the computation. A new task is -- generated only if the output of the computation is different from the -- previous one. See parallel for notes on the return value. sample :: Eq a => IO a -> Int -> TransIO a -- |
-- spawn = freeThreads . waitEvents --spawn :: IO a -> TransIO a -- | Make a transient task generator from an asynchronous callback handler. -- -- The first parameter is a callback. The second parameter is a value to -- be returned to the callback; if the callback expects no return value -- it can just be a return (). The callback expects a setter -- function taking the eventdata as an argument and returning a -- value to the callback; this function 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 generates a new task for the transient monad. react :: Typeable eventdata => ((eventdata -> IO response) -> IO ()) -> IO response -> TransIO eventdata -- | 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 :: (MonadState EventF 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 from
-- the requested type context. If the data item is not found, an
-- empty value (a void event) is returned. Remember that an empty
-- value stops the monad computation. If you want to print an error
-- message or a default value in that case, you can use an
-- Alternative composition. For example:
--
-- -- getSData <|> error "no data" -- getInt = getSData <|> return (0 :: Int) --getSData :: Typeable a => TransIO a -- | Same as getSData but with a more general type. If the data is -- found, a Just value is returned. Otherwise, a Nothing -- value is returned. getData :: (MonadState EventF m, Typeable a) => m (Maybe a) -- | Delete the data item of the given type from the monad state. delData :: (MonadState EventF m, Typeable a) => a -> m () -- | Accepts a function that 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 :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> m () -- | Run an action, if the result is a void action undo any state changes -- that it might have caused. try :: TransIO a -> TransIO a -- | Same as setData setState :: (MonadState EventF m, Typeable a) => a -> m () -- | Same as getSData getState :: Typeable a => TransIO a -- | Same as delData delState :: (MonadState EventF m, Typeable a) => a -> m () -- | Same as modifyData modifyState :: (MonadState EventF m, Typeable a) => (Maybe a -> Maybe a) -> 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. oneThread :: TransIO a -> TransIO a -- | Kill all the child threads of the current thread. killChilds :: TransIO () -- | Install an exception handler. On exception, currently installed -- handlers are executed in reverse (i.e. last in first out) order. Note -- that multiple handlers can be installed for the same exception type. onException :: Exception e => (e -> TransIO ()) -> TransIO () -- | Delete all the exception handlers registered till now. cutExceptions :: TransientIO () -- | Used inside an exception handler. Stop executing any further exception -- handlers and resume normal execution from this point on. continue :: TransIO () catcht :: Exception e => TransIO b -> (e -> TransIO b) -> TransIO b throwt :: Exception e => e -> TransIO a -- | Generator of identifiers that are unique within the current monadic -- sequence They are not unique in the whole program. genId :: MonadState EventF m => m Int 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 :: MonadIO m => EVar t -> t -> m () -- | write the EVar and drop all the readEVar handlers. -- -- It is like a combination of writeEVar and cleanEVar lastWriteEVar :: MonadIO m => EVar t -> t -> m () -- | 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, especially in finish blocks. -- -- 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
-- | Constraint type synonym for a value that can be logged.
type Loggable a = (Show a, Read a, Typeable a)
-- | Run the computation, write its result in a log in the parent
-- computation 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 logged
-- computation. Once the parent computation is finished its internal
-- (subcomputation) logs are discarded.
logged :: Loggable a => TransientIO a -> TransientIO a
received :: Loggable a => a -> TransIO ()
param :: Loggable 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 ()
-- | 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
-- | 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 the given undo track id. Performs all the -- undo actions registered till now 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 -- stops and a stop action is returned. back :: (Typeable b, Show b) => b -> TransientIO a -- | For a given undo track id, 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 () -- | 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 :: ((Maybe SomeException) -> 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 -> ((Maybe SomeException) -> TransIO a) -> TransIO a -- | Execute all the finalization actions registered up to the last -- initFinish, in reverse order. Either an exception or -- Nothing can be passed to finish. The argument passed is -- made available in the onFinish actions invoked. finish :: Maybe SomeException -> TransIO a -- | Abort finish. Stop executing more finish actions and resume normal -- execution. Used inside onFinish actions. noFinish :: TransIO () -- | Clear all finish actions registered till now. initFinish :: TransientIO ()