Al Falloon wrote:
Maybe I am misunderstanding your requirements, but it seems to me that
the simplest solution would be best in this case:
data Widget = BlogWidget [Article]
| TextWidget String
| MenuWiget Menu
| Rows Spacing [Widget]
| Columns Spacing [Widget]
You can also add a type parameter if you want to be able to carry around
extra metadata about pages, or you could even parameterize the Article
and Menu types if you want to be able to extend them separately or if
you want to ensure your layout algorithms don't depend on widget
contents by keeping their type abstract.
Thanks for pointing out a simple solution. Over thinking this is something
I'm worried about :)
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.
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.
The issue becomes, given a parent page and the customized content for
the child page,
what is the best way to insert the customized content at the right point?
Might a tree like structure be useful? But, how do you work out where
in the tree
child content gets added? Store a traversal with each sub tree of
child page content
that basically says 'insert here'?
This is probably a good use for a zipper (a kind of functional
iterator). http://en.wikibooks.org/wiki/Haskell/Zippers that way you can
pass around a value that means "right here", and its clear where the
substitution will happen.
I was wondering with zippers were appropriate, or if I just had them in mind
becuase I'd read so much about them lately :)
>
> 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
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
Thanks
Levi
lstephen.wordpress.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe