
2010/4/25 Jasper Van der Jeugt
Hey web-devel mailing list,
I'm currently working on the BlazeHtml HTML combinator library, and currently a bit stuck on a piece of API design, for which I need some community feedback. I'll try to explain the problem here as clear as possible.
The base idea is, for an HTML combinator library, that you provide combinators that the end user can use to "combine" his document. More specifically, we would have combinators for every HTML element.
So, say you have the regular div tag. This would be, in our library, Text.Blaze.Html.Strict.div. That makes sense, but it seems possible that a user wants to use a div as a leaf node (e.g. `<div />`). So there are two possible signatures for `div`:
div :: Html -- An empty div element. div :: Html -> Html -- The argument is the content of the div element.
I'm not sure what we want to do in that case. I so far see two major options:
Option 1: We can provide leaf and non-leaf combinators for every tag. I'm not sure if this is overkill or not, but it is, for example not forbidden to have content in an `<img>` tag. We could have these functions in Text.Blaze.Html.Strict and Text.Blaze.Html.Strict.Leaf, for instance. But it must be kind of annoying for the end user to have to write `L.div` instead of just `div`. On the other hand, if we put the *common* uses for the tags (e.g. `img` as leaf, `div` as non-leaf) in the main module, we would get a very inconsistent mess, I assume.
So this solution would include: - a module of html combinators as non-leaf elements - a module of html combinators as leaf-elements - the possibility for the end-user to import and qualify them as he/she sees fit; or - add a module with the most common uses and re-export the combinators
Option 2: We could only support parent nodes (of the type `Html -> Html`), and introduce another combinator:
(/>) :: Html (/>) = mempty
I have chosen `/>` here because it resembles the end of a leaf HTML tag (e.g. `<img />`). Then, we would introduce a custom rule.
{-# RULES "tag/empty" forall x y. tag x y (/>) = leaf x #-}
The `y` here is the closing tag, we pass it as an argument for performance reasons, and you can safely ignore it. This code results in the fact that if we write
img (/>)
somewhere in our template, it would be rendered to `<img></img>` when we don't pass `-fenable-rewrite-rules` to the compiler, and `<img />` otherwise. Note that `-O` implies `-fenable-rewrite-rules`. I'm not sure about this solution either, because it sort of feels like a (slightly elegant) hack.
I have my doubts with both options, but I would tend to go for (1), because (2) feels more unstable. Anyway, feedback and more ideas would be appreciated :-)
Kind regards, Jasper Van der Jeugt _______________________________________________ web-devel mailing list web-devel@haskell.org http://www.haskell.org/mailman/listinfo/web-devel
I like the idea of having a definition for (/>) but at the same time I think you're overthinking this. I would just append an apostrophe to the names of functions that are "self-closing". div = "<div></div>" div' = "<div/>" etc. -- Deniz Dogan