[Haskell-cafe] Re: I'm stuck in my thought experiment
levi.stephen at optusnet.com.au
Mon Aug 20 20:17:19 EDT 2007
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
More information about the Haskell-Cafe