Initial Thoughts
Duncan has pointed out that we’d like to re-implement my Mogul stuff for creating tree/lists widgets, hopefully using a more Attr-like style. The problem with the current Mogul stuff is that it provides constructors that return functions to read and write the cell values. Each pair of read-write function has a type that corresponds to the data stored at the specific column. Although this is very object-oriented, it means you have to keep two functions around for each column in the tree model. This is a pain since the read and write functions have to be passed to every function that manipulates the list/tree. It would be more convenient if phantom types or type classes could be used to ensure type-correct access. This is very appealing since the (type of the) columns of a tree model must be static anyway.
(Note that this does not mean that the set of columns that are shown is static; what columns are visible is determined by the view, not the model.)
Here is the framework:
- a visible column is drawn by a cell renderer
- each cell renderer has several attributes, e.g. the text of the cell and the foreground colour
- while the foreground colour attribute can be the same for all rows, some attributes (like the text) should be different for each row; these changing attributes are retrieved from the model
- the model contains a column for each of the changing attributes, and several rows that make up the actual data of the list or tree
What we aim for is a type-safe interface to access the different columns in the model. As mentioned above, the set of columns in a tree model are determined at creation time. One idea I had was to use a nested phantom type to represent the types of the columns. For example, a model that contains two String columns and one Pixbuf column could have the type
TreeModel (Column String (Column String (Column Pixbuf ())))
where Column is some empty newtype constructor. One problem I see with this approach is that accessing the nth column cannot be expressed. Instead one would have to define function to read or write a specific column, e.g.
readFirst :: TreeModel (Column val a) -> IO val
readSecond :: TreeModel (Column a (Column val b)) -> IO val
which obviously imposes a hard limit on the number of columns a program could defined. Suggestions welcome.