[Haskell-cafe] Call for GUI examples - Functional Reactive Programming
John Lato
jwlato at gmail.com
Sat Jul 9 17:58:16 CEST 2011
From: Chris Smith <cdsmith at gmail.com>
>
> On Fri, 2011-07-08 at 08:08 +0200, Heinrich Apfelmus wrote:
> > Do you know any *small GUI programs* that you would *like* to see
> > *implemented with Functional Reactive Programming?*
>
> This isn't really a specific application, but what I'd like to see most
> from FRP is an example of something that involves moving between windows
> and dialog boxes. All of the GUI-based FRP examples I've seen so far
> involve interactions in a specific GUI layout. It's unclear to me how
> FRP extends into a situation like:
>
> - There's a starting window showing several options for what to do
> - When the user chooses an option, that window closes, and a new one
> opens with that activity.
> - In response to some actions, dialog boxes appear with their own
> interactions.
>
> It's not clear to me if anyone in FRP has an idea of how stuff like this
> fits in. Is there some FRP trick to handle this declaratively? Or
> would you just say each move to a new window ends or pauses one network
> of events and behaviors, and starts a new one?
I can show you how I've been handling this with reactive-banana and
gtk2hs. As a small example, the "File->Open" command is meant to open
a new project. The codez:
> maybeEvent0 :: Typeable a => Action -> IO (Maybe a) -> NetworkDescription (Event a)
> maybeEvent0 act ops = do
> (addHandler, runHandlers) <- liftIO newAddHandler
> liftIO $ on act actionActivated $ ops >>= maybe (return ()) runHandlers
> fromAddHandler addHandler
> -- | Load a saved project file
> openHandler :: ActionGroup -> Window -> NetworkDescription (Event (String, HTree))
> openHandler actGrp _win = do
> act <- liftIO openAction
> liftIO $ actionGroupAddActionWithAccel actGrp act Nothing
> maybeEvent0 act openProjectDialog
> openProjectDialog :: IO (Maybe (String, HTree))
> openProjectDialog = do
> fc <- fileChooserDialogNew (Just "Select a project file")
> Nothing
> FileChooserActionOpen
> []
> fileChooserSetSelectMultiple fc False
> dialogAddButton fc stockCancel ResponseCancel
> dialogAddButton fc stockOk ResponseOk
> widgetShowAll fc
> resp <- dialogRun fc
> case resp of
> ResponseOk -> runMaybeT $ do
> fp <- MaybeT $ fileChooserGetFilename fc
> liftIO $ widgetDestroy fc
> (fp, ) <$> liftIO (readProject fp)
> _ -> widgetDestroy fc >> return Nothing
The `openHandler` function connects the Gtk signal to the
reactive-banana framework. This uses the helper `maybeEvent0`, which
filters an IO action and triggers a reactive-banana Event when that IO
action actually returns a value.
I've been using this pattern for most of my modal dialogs, and I think
it works very well. The one dialog I haven't used it for is the
starting window, which is straight-line imperative code.
I don't yet have any non-modal dialogs or alternate windows, but there
shouldn't be a problem. There's nothing special about which window a
widget is in; it can be connected to the FRP framework just like a
widget in the main window.
John L.
More information about the Haskell-Cafe
mailing list