[web-devel] BlazeHtml: a question about API design

Deniz Dogan deniz.a.m.dogan at gmail.com
Sun Apr 25 05:05:46 EDT 2010


2010/4/25 Jasper Van der Jeugt <jaspervdj at gmail.com>:
> 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 at 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


More information about the web-devel mailing list