-- 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.6.3 -- | See http://github.com/agocorona/transient Everything in this -- module is exported in order to allow extensibility. module Transient.Internals tshow :: Show a => a -> x -> x (!>) :: 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 -- | 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) -- | 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) 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 :: 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 -- | 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)] -- | 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] type Hash = Int data LogElem Wait :: LogElem Exec :: LogElem Var :: IDynamic -> LogElem data Log Log :: Recover -> CurrentPointer -> LogEntries -> Hash -> 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 -- | 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 infixr 1 <*** infixr 1 <** infixr 1 **> -- | 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) => 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) => 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 :: MonadState EventF 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 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 by the -- data type. If the data item is not found, empty is executed, so the -- alternative computation will be executed, if any, or Otherwise, the -- computation will stop.. If you want to print an error message or a -- default value, you can use an Alternative composition. For -- example: -- --
--   getSData <|> error "no data of the type desired"
--   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 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 :: (MonadState EventF 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' :: (MonadState EventF m, Typeable a) => (a -> a) -> a -> m a -- | 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 () newtype Ref a Ref :: IORef a -> Ref 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, MonadState EventF m, Typeable a) => a -> m () getRData :: (MonadIO m, MonadState EventF 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 it -- might have caused 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 :: 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 -- | A 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 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 -- before any alternative computation. 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 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. 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 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 () -- | 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 the rest of the computation in a new thread. Returns empty -- to the current thread abduce :: TransIO () -- | 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 to the user 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 -- | inputf after sucessful or not identifier default -- value proc inputf :: Loggable a => Bool -> 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 -> IO ())] addListener :: String -> (String -> IO ()) -> IO () delListener :: String -> IO () reads1 :: (Typeable a, Read a) => [Char] -> [(a, String)] read1 :: (Typeable a, Read a) => [Char] -> a rprompt :: IORef [Char] inputLoop :: () => IO b rconsumed :: IORef Bool lineprocessmode :: IORef Bool processLine :: [Char] -> IO () -- | 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: -- --
    --
  1. ps: show threads
  2. --
  3. log: inspect the log of a thread
  4. --
  5. end, exit: terminate the program
  6. --
-- -- An input not handled by the command handler can be handled by the -- program. -- -- The program's command line is scanned for -p or -- --path command line options. The arguments to these options -- are injected into the async input channel as keyboard input to the -- program. Each line of input is separated by a /. For example: -- --
--   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 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 () -- | 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 a -> (a -> 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 directly involved in the connection. -- Perhaps it was initiated after the socket is being 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) 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) -- | 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 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.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.ParseError instance GHC.Show.Show Transient.Internals.LifeCycle instance GHC.Classes.Eq Transient.Internals.LifeCycle instance GHC.Exception.Type.Exception Transient.Internals.Finish instance GHC.Base.Functor Transient.Internals.StreamData instance Transient.Internals.AdditionalOperators Transient.Internals.TransIO instance GHC.Base.Applicative 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.Exception.Type.Exception Transient.Internals.ParseError instance Control.Monad.State.Class.MonadState Transient.Internals.EventF Transient.Internals.TransIO instance GHC.Base.Functor 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.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 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 a task set, grouping all results received -- within every time interval specified by the first parameter as -- diffUTCTime. -- -- 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] groupByTime :: Monoid a => Int -> TransIO a -> TransIO 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 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. -- --

Overview

-- -- The TransientIO monad allows you to: -- -- -- -- You can think of TransientIO as a concurrent list transformer -- monad with many other features added on top e.g. backtracking, logging -- and recovery to move computations across machines for distributed -- processing. -- --

Non-determinism

-- -- In its non-concurrent form, the TransientIO monad behaves -- exactly like a list transformer monad. It is like a list whose -- elements are generated using IO effects. It composes in the same way -- as a list monad. Let's see an example: -- --
--   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. -- --

Concurrency

-- -- TransientIO monad is a concurrent list transformer i.e. each -- element of the generated list can be processed concurrently. In the -- previous example if we change the number of threads to 10 we can see -- concurrency in action: -- --
--   ...
--   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. -- --

Composing Tasks

-- -- The type TransientIO a represents a task set with each -- task in the set returning a value of type a. A task set could -- be finite or infinite; multiple tasks could run -- simultaneously. The absence of a task, a void task set or failure is -- denoted by a special value empty in an Alternative -- composition, or the stop primitive in a monadic composition. In -- the transient programming model the programmer thinks in terms of -- tasks and composes tasks. Whether the tasks run synchronously or -- concurrently does not matter; concurrency is hidden from the -- programmer for the most part. In the previous example the code written -- for a single threaded list transformer works concurrently as well. -- -- We have already seen that the Monad instance provides a way to -- compose the tasks in a sequential, non-deterministic and concurrent -- manner. When a void task set is encountered, the monad stops -- processing any further computations as we have nothing to do. The -- following example does not generate any output after "stop here": -- --
--   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
--   
-- --

Parallel Map Reduce

-- -- The following example uses choose to send the items in a list -- to parallel tasks for squaring and then folds the results of those -- tasks using collect. -- --
--   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)
--   
-- --

State Isolation

-- -- State is inherited but never shared. A transient application is -- written as a composition of task sets. New concurrent tasks can be -- triggered from inside a task. A new task inherits the state of the -- monad at the point where it got started. However, the state of a task -- is always completely isolated from other tasks irrespective of whether -- it is started in a new thread or not. The state is referentially -- transparent i.e. any changes to the state creates a new copy of the -- state. Therefore a programmer does not have to worry about -- synchronization or unintended side effects. -- -- The monad starts with an empty state. At any point you can add -- (setData), retrieve (getSData) or delete -- (delData) a data item to or from the current state. Creation of -- a task branches the computation, inheriting the previous state, -- and collapsing (e.g. collect) discards the state of the tasks -- being collapsed. If you want to use the state in the results you will -- have to pass it as part of the results of the tasks. -- --

Reactive Applications

-- -- A popular model to handle asynchronous events in imperative languages -- is the callback model. The control flow of the program is driven by -- events and callbacks; callbacks are event handlers that are hooked -- into the event generation code and are invoked every time an event -- happens. This model makes the overall control flow hard to understand -- resulting into a "callback hell" because the logic is distributed -- across various isolated callback handlers, and many different event -- threads work on the same global state. -- -- Transient provides a better programming model for reactive -- applications. In contrast to the callback model, transient -- transparently moves the relevant state to the respective event threads -- and composes the results to arrive at the new state. The programmer is -- not aware of the threads, there is no shared state to worry about, and -- a seamless sequential flow enabling easy reasoning and composable -- application components. Axiom is a client and server side web -- UI and reactive application framework built using the transient -- programming model. -- --

Further Reading

-- -- module Transient.Base data TransIO a type TransientIO = TransIO -- | Run m a discarding its result before running m b. (**>) :: AdditionalOperators m => m a -> m b -> m b infixr 1 **> -- | Run m b discarding its result, after the whole task set m -- a is done. (<**) :: AdditionalOperators m => m a -> m b -> m a infixr 1 <** -- | 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 infixr 1 <*** -- | 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: -- --
    --
  1. ps: show threads
  2. --
  3. log: inspect the log of a thread
  4. --
  5. end, exit: terminate the program
  6. --
-- -- An input not handled by the command handler can be handled by the -- program. -- -- The program's command line is scanned for -p or -- --path command line options. The arguments to these options -- are injected into the async input channel as keyboard input to the -- program. Each line of input is separated by a /. For example: -- --
--   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 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 to the user 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 -- | 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 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 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 -- before any alternative computation. See parallel for notes on -- the return value. async :: IO a -> TransIO a -- | A 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 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. 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 -- | Runs the rest of the computation in a new thread. Returns empty -- to the current thread abduce :: TransIO () -- | 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 by the -- data type. If the data item is not found, empty is executed, so the -- alternative computation will be executed, if any, or Otherwise, the -- computation will stop.. If you want to print an error message or a -- default value, you can use an Alternative composition. For -- example: -- --
--   getSData <|> error "no data of the type desired"
--   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 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 :: (MonadState EventF 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' :: (MonadState EventF m, Typeable a) => (a -> a) -> a -> m a -- | Run an action, if it does not succeed, undo any state changes that it -- might have caused and allow aternative actions to run with the -- original state 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 () 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, 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. 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 -- | 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 -- | 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 -- | 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: -- -- -- -- Backtracking works seamlessly across thread boundaries. The freedom to -- put the undo, exception handling and finalization code where we want -- it allows us to write modular and composable code. -- -- Note that backtracking (undo, finalization or exception handling) does -- not change or automatically roll back the user defined state in any -- way. It only executes the user installed handlers. State changes are -- only caused via user defined actions. Any state changes done within -- the backtracking actions are accumulated on top of the user state as -- it was when backtracking started. This example prints the final state -- as "world". -- --
--   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 () -- | 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 => TransIO a -> TransIO 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 fromIDyn :: Loggable a => IDynamic -> a maybeFromIDyn :: Loggable a => IDynamic -> Maybe a toIDyn :: (Show a, Read a, Typeable a) => a -> IDynamic module Transient.Parse -- | set a stream of strings to be parsed setParseStream :: IO (StreamData ByteString) -> TransIO () -- | set a string to be parsed setParseString :: ByteString -> TransIO () withParseString :: ByteString -> TransIO a -> TransIO a -- | 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 ParseContext :: IO (StreamData str) -> str -> ParseContext str -- | succeed if read the string given as parameter string :: ByteString -> TransIO ByteString -- | fast search for a token tDropUntilToken :: ByteString -> TransIO () tTakeUntilToken :: ByteString -> TransIO ByteString -- | read an Integer integer :: TransIO Integer -- | read an Int int :: TransIO Int -- | read many results with a parser (at least one) until a end -- parser succeed. manyTill :: TransIO a -> TransIO b -> TransIO [a] chainManyTill :: (Alternative f, Monad f, Monoid a1) => (t -> a1 -> a1) -> f t -> f a2 -> f a1 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] semiSep1 :: () => TransIO a -> TransIO [a] dropSpaces :: TransIO () dropTillEndOfLine :: TransIO () parseString :: TransIO ByteString -- | take characters while they meet the condition tTakeWhile :: (Char -> Bool) -> TransIO ByteString -- | take characters while they meet the condition and drop the next -- character tTakeWhile' :: (Char -> Bool) -> TransIO ByteString just1 :: () => (p -> (a, b)) -> p -> (Maybe a, b) -- | take n characters tTake :: Int64 -> TransIO ByteString -- | drop n characters tDrop :: Int64 -> TransIO () -- | read a char anyChar :: TransIO Char -- | verify that the next character is the one expected tChar :: Char -> TransIO Char -- | bring the lazy byteString state to a parser and actualize the -- byteString state with the result The tuple that the parser should -- return should be : (what it returns, what should remain to be parsed) withData :: (ByteString -> TransIO (a, ByteString)) -> TransIO a -- | bring the data of the parse context as a lazy byteString giveData :: TransIO ByteString -- | True if the stream has finished isDone :: TransIO Bool -- | 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 ByteString) -> TransIO b -> TransIO b