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.
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe