
Alexander Solla wrote:
So, the type (View view) -- ignoring class instances -- is basically isomorphic to this (slightly simpler) type:
data View = EmptyView | TextView String | ConcatView View View | NestViews View View View | ... instance Monoid View where ...
Now, consider the problem of "generic programming" on the simpler type: you quantify over the data constructors "generically", and in doing so you gain "traversals" for the type.[1] You gain the same things by turning View into (View view) -- a functor, a foldable functor, and so on. When it comes time to "render" a format for a View (for example, a bit of Html from Text.XHtml.Strict), I use some higher order functions I'm already familiar with. Something like
renderXHtml :: (View view) -> Html renderXHtml (ConcatViews l r) = fold $ renderXHtml (ConcatViews l r) renderXHtml (NestViews l m r) = fold $ renderXHtml (NestViews l m r) renderXHtml (TextView string) = stringToHtml string renderXHtml (PageView v_title, v_heading, v_header, v_footer, v_contents) = (the_title << (renderXHtml v_title)) +++ -- (We assume v_title is a TextView String) (body << ( renderXHtml v_header ) +++ (render_page_contents v_contents v_heading) +++ (renderXHtml v_footer) ) where render_page_contents contents heading = undefined
But isn't the line renderXHtml (ConcatView l r) = fold $ renderXHtml (ConcatViews l r) a type error? I'm assuming Data.Foldable.fold :: (Foldable m, Monoid t) => m t -> t being applied to the result type of renderXHtml which is Html and not of the form m t . Your intention reminds me of the use of type variables to get functor-like behavior for free, like in data RGB' a = RGB a a a -- auxiliary type constructor type RGB = RGB' Int -- what we're interested in instance Functor RGB' where fmap f (RGB x y z) = RGB (f x) (f y) (f z) mapRGB :: (Int -> Int) -> RGB -> RGB mapRGB = fmap but I don't quite see what you're doing with the free monad here, Alexander? Regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com