Thanks for all you comments about optional parameters.
Heres the solution I finally adopted.
In HTML, tags nest more HTML. So, one model is to represent tags using
functions. so we might have
small :: Html -> Html
italics :: Html -> Html
paragraph :: Html -> Html
Some Html objects do not have embedded Html, like:
txt :: String -> Html
So one might write
paragraph (small (italics (txt "Hello, World")))
or
paragraph . small . italics $ txt "Hello, World"
The problem here is how do you add optional parameters,
like paragraph alignment.
Adopted solution. Consider an operator:
infixr 7 <<
(<<) :: (HTML a,HTML b) => a -> b -> Html
This reads "nests", so we write
paragraph << small << italics << "Hello, World"
and read this as 'paragraph nests small, which nests italics, which
nests "Hello, World"'.
Now define the class HTML.
class HTML a where
html :: a -> Html
This is a method for translating any object that has
an instance of HTML into a (real) Html object.
The definition over Html itself is trivial.
We can also define HTML over String.
instance HTML Html where
html a = a
instance HTML String where
html s = stringToHtml s
Our primitive functions have types like:
small :: [HtmlAttr] -> Html -> Html
italics :: [HtmlAttr] -> Html -> Html
paragraph :: [HtmlAttr] -> Html -> Html
where HtmlAttr are things like
alignment, etc.
The above example could be written:
paragraph [] << small [] << italics [] << "Hello, World"
This is ugly, because of the needless []. So we define a new
instance of HTML.
instance (HTML a) => HTML ([HtmlAttr] -> a) where
html f = html (f [])
This means that anything expecting an HTML will also accept
an object that takes a list of HtmlAttr, and returns an HTML object.
So we can write:
paragraph << small << italics << "Hello, World"
This works because of the type of (<<), which takes objects
of that are members of the HTML class, and uses the above
"[HtmlAttr] -> a" instance to apply an empty argument list.
We can also write:
paragraph [align "right"] << small << italics << "Hello, World"
Other tricks, like the restrictions on arguments types, using
classes, could also be used.
Andy