rasa-0.1.8: A modular text editor

Safe HaskellNone
LanguageHaskell2010

Rasa.Internal.Async

Synopsis

Documentation

asyncEventProvider :: (Dispatcher -> IO ()) -> Action () Source #

This allows long-running IO processes to provide Events to Rasa asyncronously.

Don't let the type signature confuse you; it's much simpler than it seems.

Let's break it down:

(Dispatcher -> IO ()): Dispatcher is a type alias just to make defining your own functions easier; Using Dispatcher with asyncEventProvider requires the Rank2Types language pragma.

This type as a whole represents a function which accepts a Dispatcher and returns an IO; the dispatcher itself accepts data of ANY Typeable type and emits it as an event (see the Rasa.Internal.Events).

When you call asyncEventProvider you pass it a function which accepts a dispatch function as an argument and then calls it with various events within the resulting IO.

Note that asyncEventProvider calls forkIO internally, so there's no need to do that yourself.

Here's a simple example which fires a Timer event every second.

{-# language Rank2Types #-}
data Timer = Timer
myTimer :: Dispatcher -> IO ()
myTimer dispatch = forever $ dispatch Timer >> threadDelay 1000000

myAction :: Action ()
myAction = onInit $ asyncEventProvider myTimer

type Dispatcher = forall a. Typeable a => a -> IO () Source #

This is a type alias to make defining your event provider functions easier; It represents the function your event provider function will be passed to allow dispatching events. Using this type requires the Rank2Types language pragma.

asyncActionProvider :: ((Action () -> IO ()) -> IO ()) -> Action () Source #

Don't let the type signature confuse you; it's much simpler than it seems. The first argument is a function which takes an action provider; the action provider will be passed a dispatch function which can be called as often as you like with Action ()s. When it is passed an Action it forks off an IO to dispatch that Action to the main event loop. Note that the dispatch function calls forkIO on its own; so there's no need for you to do so.

Use this function when you have some long-running process which dispatches multiple Actions.

dispatchEventAsync :: Typeable a => IO a -> Action () Source #

This function takes an IO which results in some Event, it runs the IO asynchronously and dispatches the event

dispatchActionAsync :: IO (Action ()) -> Action () Source #

dispatchActionAsync allows you to perform a task asynchronously and then apply the result. In dispatchActionAsync asyncAction, asyncAction is an IO which resolves to an Action, note that the context in which the second action is executed is NOT the same context in which dispatchActionAsync is called; it is likely that text and other state have changed while the IO executed, so it's a good idea to check (inside the applying Action) that things are in a good state before making changes. Here's an example:

asyncCapitalize :: Action ()
asyncCapitalize = do
  txt <- focusDo $ use text
  -- We give dispatchActionAsync an IO which resolves in an action
  dispatchActionAsync $ ioPart txt

ioPart :: Text -> IO (Action ())
ioPart txt = do
  result <- longAsyncronousCapitalizationProgram txt
  -- Note that this returns an Action, but it's still wrapped in IO
  return $ maybeApplyResult txt result

maybeApplyResult :: Text -> Text -> Action ()
maybeApplyResult oldTxt capitalized = do
  -- We get the current buffer's text, which may have changed since we started
  newTxt <- focusDo (use text)
  if newTxt == oldTxt
    -- If the text is the same as it was, we can apply the transformation
    then focusDo (text .= capitalized)
    -- Otherwise we can choose to re-queue the whole action and try again
    -- Or we could just give up.
    else asyncCapitalize