[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