
Levi Stephen:
[...] I was imagining a drag and drop web page designer. There are a bunch of Widgets (e.g., BlogWidget, TextWidget, MenuWidget, etc) that the user can place on the page. [...]
class Widget a where render :: a -> Html
-- A page has a title and a Widget. -- I know this isn't valid Haskell, but I'm not sure how to specify what I -- want here. (existential types?) data Page = Page String Widget
If you wanted to make Page an existential type, it would look like this: data Page = forall w . Widget w => Page String w However, you will probably find it much more useful to define a single existential wrapper for all widgets: data WidgetW = forall w . Widget w => WidgetW w Then, for example, you can construct polymorphic lists of widgets, as is necessary for the column layout: data Columns = Columns [WidgetW] -- hmm, needs spacing info. And now Page just adds a string to a WidgetW: data Page = Page String WidgetW See the GHC users guide for more on how to use existential types.
[...]
layout = Page "Main" (ColumnLayoutWidget [MenuWidget, ??? ]) mainPage = ChildPage layout [TextWidget mainPageText] aboutPage = ChildPage layout [TextWidget aboutPageText]
Layout just looks like a function. Assuming an existing global menu definition: layout ws = WidgetW (Page "Main" (WidgetW (Columns (menu : ws)))) Note the type of layout: a function taking a list of widgets and returning a single widget. You'll find a number of similar types useful for structuring your code. For example, functions taking a single widget and returning a single (more complex) widget, functions taking a single widget and a list of functions each taking a widget and returning a widget, and returning a list of widgets, and so on. It's called functional programming for a reason. :-)
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.
Indeed, abstractions of this kind usually require a fair amount of thought and experiment. I haven't given it either of these, but hopefully the suggestions will help you become less stuck.