Haskell, electronics et al.

Main menu

Post navigation

Composable Value Editors

Graphical User Interfaces (GUIs) in haskell are frustrating. It’s not yet clear what is the cleanest model for fitting GUIs into functional programming. Currently there are two main approaches:

Various effort at applying Functional Reactive Programming (FRP) to GUIs. These are somewhat experimental, and tend to be proof of concepts implementing a small range of GUI features (several of these libraries are listed here).

The full blown toolkits which provide a comprehensive imperative binding to mainstream toolkits. The two key contenders here are gtk2hs and wxHaskell.

Whilst enticing, the FRP approach doesn’t currently look appropriate for building rich GUI applications. wxHaskell and gtk2hs at least provide the functionality required, but the low level imperative approach based in the IO monad is tedious to a fluent haskell developer. Here’s a code snippet:

It’s not hard to write this sort of code, but it is tedious, especially considering the amount that is required to build a whole application.

This post outlines my experiments to reduce the amount of imperative code required for GUIs, yet retaining compatibility with the imperative toolkits. Initially I’ve been focussed on "value editors" (VEs) aka "forms". These are GUI components to capture/edit values of ideally arbitrary complexity. I’ve two key goals, composability and abstraction.

Composability: I want to be able to compose my value editors effortlessly. Whilst the existing toolkits let you compose widgets using containers and glue code, it’s verbose indeed.

Abstraction: I’d like to define my VEs independently from the underlying toolkit. But I’m looking for something more than a thin layer over the existing toolkits. I want to define my VEs in terms of the structure of the values involved, and worry about the formatting and layout later, if at all.

If we take this abstraction far enough, it should be possible to reuse our structural VEs definitions beyond gtk2hs and wxWindows. For example, a JSON generator+parser pair can be considered a VE – in the sense that to edit a value, one can generate the json text, edit the text, and then parse to recover the new value. Of course, it’s likely to be a balancing act between abstraction and functionality – we’ll have to see how this pans out.

invalid fields have a red background, dynamically updated with each keystroke

Fields have sensible defaults – often invalid to force entry from a user

More complex UIs are of course possible. As should be clear from the VE GADT above we support sum and product types, lists, etc, and can map these with arbitrary code. Hence we can construct GTK UIs for a very large range of haskell values. A slightly more complex example composes the previous VE:

Related Work

Well into working on these ideas, I was reminded of two somewhat similar haskell projects: Functional Forms and Tangible Values. Functional Forms aims to ease the creation of wxHaskell dialogs to edit values. The exact purpose Tangeable Values is a little unclear to me, but it appears to be about automatically generating UIs suitable for visualising function behaviour and exploring functional programming.

Future Work

Currently I have a library that implements the VE GADT to automatically build GTK editors and JSON serialisers. There’s many ways to progress this work. Some of my ideas follow…

Whilst the generated GTK editor is a sensible default, there are only very limited ways in which the editor can be customised. I envisage a model where the uiGTK function takes an extra parameter akin to a style sheet, given extra information controlling the UI layout and formatting, etc.

I can envisage many other useful things that could automatically be derived from VE definitions:

equivalent functionality for wxHaskell

console GUIs

Funky UIs implemented with primitives more interesting than the standard toolkit widgets: eg zoomable UIs, or UIs more suited to table based platforms.

web GUIs. This could be done by automatically generating javascript and corresponding server side haskell code.

Finally, It might be worth investigate whether the GHC Generic mechansism might be used to automatically generate VE definitions.

So there’s plenty of directions this work can go, but right now I want to put it to the test and build an application!

15 thoughts on “Composable Value Editors”

Hi, I’m the author of the reactive-banana FRP library. One of its selling points is that it fits on top of any GUI framework (with some glue code), and you can always fall back to an imperative style if you feel the need to do so.

Have a look at my collection of example GUI programs. It appears to me that reactive-banana is powerful enough to describe user interfaces that are much richer than the fairly rigid value editors.

Thanks. I will take a look at the reactive-banana library – I didn’t realise that it was ready for prime time.

Whilst I agree that value editors are somewhat rigid, this can be desirable. I have previously built a (proprietary) application in python that has a richly interactive core, but is supported by dozens of value editors. Having a framework to make these VEs consistent and trivial to implement can provide much value.

Whilst I’ve read a fair number of papers over the years, I have to concede that my knowledge of FRP is limited. How would a Value Editor in FRP be represented? In reactive-banana, what would be the equivalent to the GtkWidget definition?

Perhaps value editors could be automatically generated from VE definitions in the reactive-banana framework also?

The simplest way to make a “value inputter” is to create the various widgets and then obtain their values as a Behavior. To display the combined values, you can create another set of widgets and use the sink function. This is exemplified in the Arithmetic.hs example.

It’s also possible to have widgets both input and output values, but then you’re quickly in the realm of rich user interfaces. The CurrencyConverter.hs and the CRUD.hs examples demonstrate what is possible.

In other words, there is no data type in reactive-banana that directly corresponds to a value editor. Instead, the goal is to make GUI programs easier in general.

Of course, you can generate value editors in reactive-banana from their corresponding VE descriptions. You can even generate them in the underlying GUI framework and then put a little FRP glue code on top.

Sorry for the _very_ slow reply. I missed the moderation request for this comment.

Yes – you are correct. The “form like” model assumes a dialog like behavior: The controlling code calls ui_set to put a value into a form, displays it to the user, and then finally calls ui_get to extract the resulting value.

It appears to me that the type class HasVE is not very useful. In fact, I think it falls into the typeclass antipattern.

Instead of specializing a polymorphic value (mkVE :: Person), you can just use a special value personVE right away. You don’t save any keystrokes by specifying one value editor for each type as a default.

Note that you don’t need a type class to have polymorphism, you can always use an explicit combinatormaybeVE :: VE a -> VE (Maybe a)
The post Scrap your type classes explores these patterns in detail (though I don’t agree with its conclusion of abolishing type classes altogether).

The use of the type class is only to assemble a default value editor for a given type. This may or may not be useful. For instance, a pleasant default for VE (Maybe String) would be a single edit box can be left empty (so the empty string is represented as Nothing). However, you don’t get this with the default type class instance.

I’m not sure an applicative interface would work here. We need a bidirectional interface, ie
A) put a value into an editor
B) take a value out of an editor.
I think an applicative interface might be limited to constructing values only (ie B above).

My intuition is that with an applicative interface, putting a value into an editor (ie case A in my reply above), isn’t possible. I don’t have any experience with formlets libraries…. Looking at the example on this page:

in providing User (::String -> String -> Date -> User) I seem to have only told the library how to construct User value out of the components. There’s no knowledge provided of how to decompose a User value into it’s components.

Practically, Is there a function in the API that takes a value of type a and populates an existing form (of type Form a)?