
Levi Stephen wrote:
Al Falloon wrote:
This code seems to indicate that you want to be able to extend the widget types without changing this source file. This is a good goal, but it may not be worth the extra complexity.
Ideally, I'd like Widgets to be added through hs-plugins or similar. That is a ideal goal though, not a necessity.
Also, this looks a lot like the Composite pattern from OO. A rule of thumb that I use is: "if I would do this with inheritance in OO, I probably want a variant in FP". Since Composite depends on the inheritance of the composite object type, I would probably look to use a single data type with multiple constructors for the different compisites like the Widget type above.
Interesting. I've been curious how OO concepts can map to FP, as most specs (consider stuff like DOM) seem to be written with OO implementaitons in mind.
This is a very interesting discussion that could be its own text book (or flame war) as far as I can tell, the only answer everyone agrres on is "it depends". After that it gets a little hairy. For me, I find that the best method is to just come at the problem fresh using an FP approach, and don't worry about 'mapping' the concepts.
If I wanted to develop the widgets themselves separately from the layout, I would probably do something like this:
class Widget a where render :: a -> Html bbox :: a -> Size
type Layout = forall a. Widget a => Widget a | Rows Spacing [Layout] | Columns Spacing [Layout] | Grid Spacing [[Layout]]
type Page = Page String Layout
renderLayout :: Layout -> Html
renderPage :: Page -> Html
I'm unsure this gives what I'm after. I'm trying to have layouts consist of Widgets (e.g., header images, common menu), and as pages also consist of Widgets it seems like they can be modelled using a common type/construct.
Well if you want to abstract over the layout too, you can just add instance Widget Layout where render = renderLayout bbox = ... But just because you can, doesn't mean you should. I don't know the full details of your design, but what do you gain by allowing the layout to intermingle with the widgets? Is worth the extra complexity? If you treat layout as "just another widget" then it becomes harder to answer specific questions about the page layout because you have less information in your tree.
So you want some sort of wildcard element that can be substituted in later? Maybe I am misunderstanding your requirement, but if thats the behavior you want, you should check out the term-level evaluators for lambda calculus for inspiration on substitution, but I expect your requirement may be simpler than that.
I'm thinking a BlankWidget or ReplacableWidget is a fairly simple option. They could be named for the case of multiple replacements, and have a method similar to
-- src -> replacements -> result replaceWidgets :: Widget -> [(String,Widget)] -> Widget
which replaces all ReplacableWidgets in the source Widget with those specified.
Would you happen to have some links on the evaluators for lambda calculus you talk about? I'm not as familiar as I should be with lambda calculus
They are surprisingly hard to find! It must be one of those things that is so ingrained that no-one thinks to write it down. Anyway, the closest I could find to what I meant is the "Interpretive Haskell programmer" heading in "The evolution of a Haskell programmer" http://www.willamette.edu/~fruehr/haskell/evolution.hs However, now that I look at your example again, I may have been too quick to answer with "LC evaluator!" because your language only has substitution and not abstraction (defining functions) so you don't have much of the complexity to contend with. The obvious implementation of replaceWidgets will probably work fine for you.
It might be simple to have a PlaceHolderWidget. Then insertions of the child page content happens at each of those widgets.
This just gets trickier if I start considering multiple extension points for child pages and what happens when the layout/parent page changes. This is why I'm thinking I may be going along a bad path here.
Exactly. With multiple substitutions you get into issues of naming, so thats why looking at lambda calculus evaluators would be the right inspiration, but I think it may be more complicated than you need. The zipper approach might be easier.
I think I will try and investigate both approaches. I'm after the process here, rather than the end result
Good luck. You can learn a lot just by lurking on the cafe and reading some of the better blogs. The papers are also good reading, I have a "rule of 2" if I have heard the title come up twice, I read it.