Lenses for MVC framework in Haskell
haskell, model-view-controller, wpf
Solution
I've been building a large commercial application using lens-based "MVC" in Haskell.
- Purely functional data structures
- Lenses for setting and getting (and keeping the data consistent)
- A DSL for generating a view (template) tied to each lens.
This has been a great experience, and I definitely recommend the approach for detailed structure editing of complex structures.
The approach forces you to
- Not hack, but use lenses as safe interfaces to your internal model
- Strong separation of the model -> view
- Type checking for everything -- lens types to generate view code
There's lots of ways you can design it, but I think it is a very sound design approach. You will want good DSL support for the GUI part.
Problem
I've been mulling around the idea of how you'd construct a MVC framework in Haskell in the mold of WPF or AngularJS, but can't seem to find the key types or idea to get started. So unfortunately vague question - has anyone else out there been thinking about this problem? I see edit-lenses, multi-plate and Compos, but I think they all solve slightly different problems. My rough sketch of how that would work would be: - Create a model as a plain haskell data structure - Create a set of 'lenses' or commands to modify your model. - Write a HTML (or whatever) template which is parametised by the types in the model. . ``` data Model = Page { _title :: String, _content :: [(Int, String)] } title :: Lens Model String content :: Int -> Lens Model (Maybe String) ``` Then I would want to be able to write a function: ``` Model -> Template Model -> Html ``` and a function to update parts of my view when I apply a lens. ``` Lens Model a -> a -> HtmlTemplate Model -> [(Path, Html)] ``` So I guess the question is - what type would a lens take which can operate on one data structure, then be used to describe the change in another. One possibility seems to be to create a GADT which wraps all the lenses and then template the HTML over the GADT type which can then be used to match against the template at each step. e.g. ``` data Lenses a b where Title :: Lens Model String -> Lenses Model String Item :: Lens Model String -> Lenses Model (Maybe String) ``` Then a Html Template data type e.g. ``` data HtmlTemplate a = Text String | Element String [Attrib a] | forall b. Binding (Lenses a b) (Html b) ``` To which the Binding element can be pattern matched against directly. But that seems almost defeating the point, because the model is then joined at the hip to the view. I wonder has anyone (smarter than I) out there put thought into how this might work? Or even if this is a good idea?