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