What do we actually need, though? Basically, we want to map a string from an Http request into an invocation of certain code. But where do these strings come from? Typically, they come from the routes spec being used in reverse, where some view or controller code references a high-level name for a certain piece of functionality. This does the job, mostly, of ensuring that the relevant functionality is called. How about a different idea: it doesn’t really matter what string is generated, as long as it gets resolved to the right call in the end! That is, the path string just needs to contain enough information to ensure the relevant interface action is executed, and nothing else. (We could also encrypt whatever representation we use, if we want extra confidence.) What information do we need to include? One possibility is just some encoding of the actual interface operation the link represents, like some element of the UserAction type above. We probably also need some context information too for example, if working on a selected list then we need to know which list. Here’s a very useful FP concept that works well here: the Zipper [U2]. It’s an idea due to Gerard Huet that has been around for most of my lifetime. It helps with traversal and editing of functional data structures by representing a kind of cursor for where one is in a data structure, together with information for reconstructing the value after traversal. As a simple example, if one has traversed a binary tree from the root node by following left, right, right, then the zipper structure for the tree will contain the current subtree plus information for reconstructing the tree already traversed. The zipper concept can be applied to many types, demonstrated by my great friend Dr Conor McBride as the operation of taking the derivative of a datatype (yes: the concept from calculus). See this early draft [U3] for a good introduction. So, the suggestion is for each “path” in the system to be some encoding of the corresponding “state” of the interface. No separate routes file required! Controllers and Views If we can (it seems) dispense with routes, then what happens with controllers? Mostly, they will be subsumed into the interpreters for the interface actions, and so play a lesser role than in current frameworks. I would hope that much of the code seen in controllers—particularly the boilerplate code for decoding parameters, updating models and checking the results of saves—will mostly be abstracted away, possibly replaced by calls to suitably overloaded library code. We still need views, though. These will be the main way of rendering domain concepts into Html or related formats, though their use might change. I would like to see most of the rendering work done with visibly pure functions (obviously no side effects, so 100% cosmetic), preferably called through a single overloaded function. That is, all viewable things should implement the member functions of an interface like the following for standard rendering of their data, analogously to the Show class for rendering to strings. (The Html type will be provided by one of Haskell’s several libraries for Html, such as Blaze. See last month’s article for some examples of the cool features of Blaze.) PragPub January 2013 13
Previous Page Next Page