Templates as typeclasses?

In going over yet again the many failings of template frameworks for building web apps, I recalled some of the features of the best of the lot, and wondered if those features might be useful in a Haskell template framework. Python's Cheetah tool makes templates almost fully functional members of Python's OO system. A template can inherit from a Python class or another template, and a Python class can inherit from a template. Which makes me wonder if something similar might not be useful in a Haskell template framework. Possibly have each template create an appropriate datatype and make it as an instance of the Template typeclass (and possibly others). Is there already a Haskell web framework that does something like this? Would it actually add value to a framework? Thanks, Mike

You may be interested in http://hackage.haskell.org/package/shakespeare
–
Kyle Marek-Spartz
On May 8, 2014, 6:18:02 PM, Mike Meyer

I don't see it. Hamlet et al are similar to other Haskell web template system, which means similar to most other web template systems, except with better typing. The result of compiling a template isn't a type, nor is it a function of any kind - it's just data. The type of that data varies a little depending on the content, but can be identical for different templates, so there's no unique type for a template as there is with Cheetah. While the static typing one finds in haskell web template systems is better than the dynamic typing in Cheetah and other templates based on dynamically typed languages, that's inside the templates. The objects generated by the templates don't do much of anything to let the application author leverage the type system, which is what makes Cheetah stand out from other web template systems. On Thu, May 8, 2014 at 6:44 PM, Kyle Marek-Spartz < kyle.marek.spartz@gmail.com> wrote:
You may be interested in http://hackage.haskell.org/package/shakespeare
– Kyle Marek-Spartz
On May 8, 2014, 6:18:02 PM, Mike Meyer
wrote: ------------------------------ In going over yet again the many failings of template frameworks for building web apps, I recalled some of the features of the best of the lot, and wondered if those features might be useful in a Haskell template framework. Python's Cheetah tool makes templates almost fully functional members of Python's OO system. A template can inherit from a Python class or another template, and a Python class can inherit from a template.
Which makes me wonder if something similar might not be useful in a Haskell template framework. Possibly have each template create an appropriate datatype and make it as an instance of the Template typeclass (and possibly others).
Is there already a Haskell web framework that does something like this? Would it actually add value to a framework?
Thanks, Mike
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

hi,
The objects generated by the templates don't do much of anything to let the application author leverage the type system, which is what makes Cheetah stand out from other web template systems.
can you elaborate on that point? i would really like to see an example on what you mean. for another datapoint, have a look at hastache's use of generics hackage.haskell.org/package/hastache/docs/Text-Hastache.html tobias florek

On Fri, May 9, 2014 at 2:11 AM, Tobias Florek
hi,
The objects generated by the templates don't do much of
anything to let the application author leverage the type system, which is what makes Cheetah stand out from other web template systems.
can you elaborate on that point? i would really like to see an example on what you mean.
for another datapoint, have a look at hastache's use of generics hackage.haskell.org/package/hastache/docs/Text-Hastache.html
I mentioned that briefly in the original message: A Cheetah template is a Python class. It can inherit from Python classes, and Python classes can inherit from it. A standard usage is to have a page template that sets up headers and footers, and make your pages are all children of that class. While header/footer support is a stock feature of any modern templating system, Cheetah does it by leveraging it's integration into the Python class system instead of providing a specific mechanism for it. If you need something to happen on the server when the page renders - that doesn't leave any traces in the output - you can subclass the template with a standard Python class and provide that functionality. You then use the Python subclass just like a regular template. Again, the behavior isn't special, but doing it takes no special machinery, just leveraging Cheetah templates being classes. You can find simple examples of this in the Cheetah docs: http://www.cheetahtemplate.org/docs/users_guide_html_multipage/howWorks.objo...

You can do similar things with Haskell EDSL-style template systems such as Blaze, except that Haskell is not an OOP language, so you will be using different abstractions instead. Still, the big picture with these is that template building blocks are language elements, and template code and regular code can be mixed freely. The `h1` function from Blaze is just another Haskell function; it takes a MarkdownM () value and returns a MarkdownM (), and because MarkdownM happens to be a Monad, you can use do notation to sequence HTML elements. MarkdownM () is also an instance of IsString, so if you enable -XOverloadedStrings, you can use string literals to produce HTML text nodes. This means that you can write, in plain Haskell: h1 $ do span "Hello, " span "world!" ...and it'll produce <h1><span>Hello, </span><span>world!</span></h1>. For the common case where you have a "master" template and an incarnation, you could write a master template that takes its inner blocks as arguments, e.g.: masterT :: Text -> Html -> Html -> Html masterT titleText headerExtra content = do html $ do header $ do title $ toHtml titleText headerExtra body $ do h1 $ toHtml titleText div ! class_ "content" $ content footer $ "This is my super footer!" If you want something that behaves more like inheritance, the best way IMO would be to define the available blocks as a record type, e.g.: data TemplateBlocks = TemplateBlocks { tbTitleText :: Text , tbHeaderExtra :: Html , tbContent :: Html } -- Then provide some sensible defaults: defTemplateBlocks :: TemplateBlocks defTemplateBlocks = TemplateBlocks { tbTitleText = "My super web app" , tbHeaderExtra = return () , tbContent = return () } -- and then your master template becomes: masterT :: TemplateBlocks -> Html masterT tb = do html $ do header $ do title $ toHtml $ tbTitleText tb tbHeaderExtra tb body $ do h1 $ toHtml $ tbTitleText tb div ! class_ "content" $ tbContent tb footer $ "This is my super footer!" -- And then you can call it with the defaults, overriding -- as needed: masterT $ defTemplateBlocks { tbTitleText = "Homepage" , tbContent = div "Hello, world!" } Now, if you want to use template blocks *inside* template blocks, you need to alter your blocks a tiny bit in order to read other blocks into them: data TemplateBlocks = TemplateBlocks { tbTitleText :: Text , tbHeaderExtra :: TemplateBlocks -> Html , tbContent :: TemplateBlocks -> Html } -- now you could do, for example: masterT $ defTemplateBlocks { tbTitleText = "Homepage" , tbContent tb = div $ do "Hello, world!" "You are here: " toHtml $ tbTitleText tb } Now if MarkupM were implemented as a monad transformer, we could even stack it on top of a MonadReader TemplateBlocks to avoid passing the tb parameter explicitly, and lensify the whole thing, but oh well. (BTW, is anyone aware of any efforts in making Blaze into a transformer?) On Fri, May 09, 2014 at 02:34:52AM -0500, Mike Meyer wrote:
On Fri, May 9, 2014 at 2:11 AM, Tobias Florek
wrote: hi,
The objects generated by the templates don't do much of
anything to let the application author leverage the type system, which is what makes Cheetah stand out from other web template systems.
can you elaborate on that point? i would really like to see an example on what you mean.
for another datapoint, have a look at hastache's use of generics hackage.haskell.org/package/hastache/docs/Text-Hastache.html
I mentioned that briefly in the original message: A Cheetah template is a Python class. It can inherit from Python classes, and Python classes can inherit from it.
A standard usage is to have a page template that sets up headers and footers, and make your pages are all children of that class. While header/footer support is a stock feature of any modern templating system, Cheetah does it by leveraging it's integration into the Python class system instead of providing a specific mechanism for it.
If you need something to happen on the server when the page renders - that doesn't leave any traces in the output - you can subclass the template with a standard Python class and provide that functionality. You then use the Python subclass just like a regular template. Again, the behavior isn't special, but doing it takes no special machinery, just leveraging Cheetah templates being classes.
You can find simple examples of this in the Cheetah docs: http://www.cheetahtemplate.org/docs/users_guide_html_multipage/howWorks.objo...
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

Hi Mike, all.
Haskell prefer composability over inheritance. Composition is on site,
while inheritance can be hidden to the programmer and it can be too rigid.
What happens if I create my framework around a class template with header
and footer and later I need to program web services with it? I need to
create more classes for each particular problem and so on in the framework.
It is possible that these classes don´t fit the need of every particular
problem.
In the other side, a basic set of combinators can fit any problem. So
inheritance can become bad magic. While composability gives freedom.
For those of you that may not know about it, MFlow [1] templates use
composition of formlets called widgets. A MFlow page has type:
View renderingFormat monad returnValue
It is made by the applicative and monadic composition of formets with the
same type.
I can have:
import MFlow.Wai.Blaze.Html.All
myTemplate body= html <<< myheader **> body <** myfooter
where
myheader = ....
myfoother = ...
with "html" a blaze-html combinator. "myHeader" and "myfooter" are widgets.
body is the parameter widget that I give to the template.
the operator **> ignores the result of the first term like *>
if whe define:
type Widget a= View Text.Blaze.Html IO a
then:
myTemplate:: Widget a -> Widget a
I can alternatively do it using classes. I define a class:
class Template where
header:: Widget ()
body :: Widget a
footer :: Widget ()
data MyTemp a = .....
instance Template (MyTemp a) where
...
..
myTemplate mytemp= html << header mytemp **> body mytemp <** footer mytemp
It seems cumbresome, rigid and redundant to me, like many OO code..
What "header" means in that class? it includes also the html <header> tag
or it is simply some common html for all pages at the beginning? It is
probable that this class definition is not appropriate for all pages.
neither the combinator version. but with an EDSL I can create page template
variants faster for my particular problem.
But some particular problem can justify the creation of class templates in
order to enforce some requirements and make use of the extra level of
abstraction that it brings. As shown above, It is possible to do it in
Haskell and MFlow.
But this is not IMHO the right base design assumption for a (Haskell) web
framework. It may be for some particular problem.
[1] http://mflowdemo.herokuapp.com
2014-05-09 10:15 GMT+02:00 Tobias Dammers
You can do similar things with Haskell EDSL-style template systems such as Blaze, except that Haskell is not an OOP language, so you will be using different abstractions instead.
Still, the big picture with these is that template building blocks are language elements, and template code and regular code can be mixed freely. The `h1` function from Blaze is just another Haskell function; it takes a MarkdownM () value and returns a MarkdownM (), and because MarkdownM happens to be a Monad, you can use do notation to sequence HTML elements. MarkdownM () is also an instance of IsString, so if you enable -XOverloadedStrings, you can use string literals to produce HTML text nodes. This means that you can write, in plain Haskell:
h1 $ do span "Hello, " span "world!"
...and it'll produce <h1><span>Hello, </span><span>world!</span></h1>.
For the common case where you have a "master" template and an incarnation, you could write a master template that takes its inner blocks as arguments, e.g.:
masterT :: Text -> Html -> Html -> Html masterT titleText headerExtra content = do html $ do header $ do title $ toHtml titleText headerExtra body $ do h1 $ toHtml titleText div ! class_ "content" $ content footer $ "This is my super footer!"
If you want something that behaves more like inheritance, the best way IMO would be to define the available blocks as a record type, e.g.:
data TemplateBlocks = TemplateBlocks { tbTitleText :: Text , tbHeaderExtra :: Html , tbContent :: Html } -- Then provide some sensible defaults: defTemplateBlocks :: TemplateBlocks defTemplateBlocks = TemplateBlocks { tbTitleText = "My super web app" , tbHeaderExtra = return () , tbContent = return () } -- and then your master template becomes: masterT :: TemplateBlocks -> Html masterT tb = do html $ do header $ do title $ toHtml $ tbTitleText tb tbHeaderExtra tb body $ do h1 $ toHtml $ tbTitleText tb div ! class_ "content" $ tbContent tb footer $ "This is my super footer!" -- And then you can call it with the defaults, overriding -- as needed: masterT $ defTemplateBlocks { tbTitleText = "Homepage" , tbContent = div "Hello, world!" }
Now, if you want to use template blocks *inside* template blocks, you need to alter your blocks a tiny bit in order to read other blocks into them:
data TemplateBlocks = TemplateBlocks { tbTitleText :: Text , tbHeaderExtra :: TemplateBlocks -> Html , tbContent :: TemplateBlocks -> Html } -- now you could do, for example: masterT $ defTemplateBlocks { tbTitleText = "Homepage" , tbContent tb = div $ do "Hello, world!" "You are here: " toHtml $ tbTitleText tb }
Now if MarkupM were implemented as a monad transformer, we could even stack it on top of a MonadReader TemplateBlocks to avoid passing the tb parameter explicitly, and lensify the whole thing, but oh well. (BTW, is anyone aware of any efforts in making Blaze into a transformer?)
On Fri, May 9, 2014 at 2:11 AM, Tobias Florek
wrote: hi,
The objects generated by the templates don't do much of
anything to let the application author leverage the type system, which is what makes Cheetah stand out from other web template systems.
can you elaborate on that point? i would really like to see an example on what you mean.
for another datapoint, have a look at hastache's use of generics hackage.haskell.org/package/hastache/docs/Text-Hastache.html
I mentioned that briefly in the original message: A Cheetah template is a Python class. It can inherit from Python classes, and Python classes can inherit from it.
A standard usage is to have a page template that sets up headers and footers, and make your pages are all children of that class. While header/footer support is a stock feature of any modern templating system, Cheetah does it by leveraging it's integration into the Python class system instead of providing a specific mechanism for it.
If you need something to happen on the server when the page renders -
On Fri, May 09, 2014 at 02:34:52AM -0500, Mike Meyer wrote: that
doesn't leave any traces in the output - you can subclass the template with a standard Python class and provide that functionality. You then use the Python subclass just like a regular template. Again, the behavior isn't special, but doing it takes no special machinery, just leveraging Cheetah templates being classes.
You can find simple examples of this in the Cheetah docs:
http://www.cheetahtemplate.org/docs/users_guide_html_multipage/howWorks.objo...
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
-- Alberto.

What happens if I create my framework around a class template with header and footer and later I need to program web services with it? I need to create more classes for each particular problem and so on in the framework. It is possible that these classes don´t fit the need of every particular
On Fri, May 9, 2014 at 5:39 AM, Alberto G. Corona
In the other side, a basic set of combinators can fit any problem. So inheritance can become bad magic. While composability gives freedom.
Right. And good types give power. Haskell shows you can have both.
I can alternatively do it using classes. I define a class:
class Template where header:: Widget () body :: Widget a footer :: Widget ()
That might work for a single template, but as you note, it's to inflexible to use for many kinds of template. If I were going to do this (and I'm probably not), it'd be more like: class Template a where render :: String -- generate a static string of bytes -- provide instances of Monad, Monoid, and whatever else you -- think might be handy as well. instance Template Blaze.Html where render = renderHtml That's all part of the framework. Then your template system should swallow your EDSL, and produce something like: data MyPage = MyPage Template Template Template instance Template MyPage where render (MyPage head foot body) = ... (or maybe it should use a record, or a tuple, or something else). This isn't that much difference from something like Blaze. Except that the templates being datatypes instead of functions means you can make them instances of other typeclasses. I built one Cheetah template system where the templates generated config files (we had hundreds of the silly things), and made them a subclass of a FilePath type as well. So you could not only get them to provide the contents of a file, but you could get them to tell you the name of the file the content went into.
It seems cumbresome, rigid and redundant to me, like many OO code..
What "header" means in that class? it includes also the html <header> tag or it is simply some common html for all pages at the beginning? It is
Yes, but if you change it so that your typeclass just handles the thing common to all templates (rendering), and your template data types have the elements specific to them, it becomes less so. The question is does doing it this way buy you anything, and is that enough to justify the extra mechanisms involved? probable that this class definition is not appropriate for all pages. neither the combinator version. but with an EDSL I can create page template variants faster for my particular problem. The class no longer has "header", the data type does. And it means what the data type needs it to.
But this is not IMHO the right base design assumption for a (Haskell) web framework. It may be for some particular problem.
That may well be the case, even if you get the architecture closer to what Cheetah is doing. That's what I'm trying to find out. Thanks, Mike

On Fri, May 9, 2014 at 3:15 AM, Tobias Dammers
You can do similar things with Haskell EDSL-style template systems such as Blaze, except that Haskell is not an OOP language, so you will be using different abstractions instead.
All true, and things like Blaze are much nicer than most template systems. I've even got a Python templating system using an architecture similar to blaze (html tags are composeable functions) that fit in between the two. However, that's about the syntax for creating templates, not their fundamental nature. And of course this would use different abstractions. What's interesting isn't the abstractions, it's that they're obtained by moving templates into the type system. To take a step back: In most template systems (including Blaze), "template" is a type provided by the system, and you create an element of that type which you can then combine in some way with data to render, creating something that can be sent to a web browser. Exactly how "render" is implemented varies from system to system: methods on the template class, macros, and functions you pass a template to have all been used. In Cheetah, template is an abstract base class (typeclass being the closest Haskell analogue). A template is a class that implements that ABC (a datatype that's an instance of the typeclass in Haskell). You can treat it just like any other class. That includes creating an instance of the class (an element of the datatype) that can then be combined with data and rendered.
Still, the big picture with these is that template building blocks are language elements, and template code and regular code can be mixed freely.
And the big picture for Cheetah is that the template building blocks are TYPE elements. That's what's interesting. The functionality that falls out of it naturally depends on the type system, and is generally uninteresting. The questions I'd actually like answered is whether any Haskell template system uses a similar architecture, and whether doing so provides any interesting functionality.
If you want something that behaves more like inheritance,
I don't. As stated above, that's uninteresting. I doubt if a web app developer ever wanted inheritance. Or a monad. Any more than a carpenter ever wanted a 10mm drill bit.
Now if MarkupM were implemented as a monad transformer, we could even stack it on top of a MonadReader TemplateBlocks to avoid passing the tb parameter explicitly, and lensify the whole thing, but oh well. (BTW, is anyone aware of any efforts in making Blaze into a transformer?)
And if MarkupM were a typeclass, and your templates a datatype, then
you could think about implementing your templates as monad
transformers, instead of needing it to be done in MarkupM.
Thanks,

I think what you're after is a template language implemented as an EDSL, that is, a domain-specific language embedded in the host language, such that the template language's building blocks are language constructs in the host language. The various Haskell template systems take varying approaches here. The ones I can think of are: - EDSL's, like Blaze, where templates are Haskell functions composed of other Haskell functions. E.g.: `myTemplate = div $ do { h1 "hello"; p $ toHtml $ toNameCase username }` - Quasi-quoters, where the parsed template gets injected into the host Haskell code at compile time, before type checking even. Some of these have syntax constructs for popping Haskell code back into the template. Example: `[template|<h1>Hello</h1><p>{{ toNameCase username }}</p>|] - Preprocessors, where you run your Haskell source through an external tool before compiling it. Example: `template = <h1>"Hello"</h1> <p>toNameCase username</p>` - Full-on templates, where you feed template source to a template compiler or interpreter with an explicit context, e.g.: `runTemplate "myTemplate.tpl" [("username", toNameCase username)]` I think it should even be possible to build some sort of hybrid that can run in several modes, e.g. you'd run it through an interpreter during development (for faster development cycles, skipping the build step), but for production you compile them into your binary (for easier deployment, better performance, and static type checks). I haven't seen anything like that though so far, at least not industry-strength. Have experimented with the idea myself, but then again, the result isn't quite there yet. On Thu, May 08, 2014 at 06:18:02PM -0500, Mike Meyer wrote:
In going over yet again the many failings of template frameworks for building web apps, I recalled some of the features of the best of the lot, and wondered if those features might be useful in a Haskell template framework.
Python's Cheetah tool makes templates almost fully functional members of Python's OO system. A template can inherit from a Python class or another template, and a Python class can inherit from a template.
Which makes me wonder if something similar might not be useful in a Haskell template framework. Possibly have each template create an appropriate datatype and make it as an instance of the Template typeclass (and possibly others).
Is there already a Haskell web framework that does something like this? Would it actually add value to a framework?
Thanks, Mike
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (5)
-
Alberto G. Corona
-
Kyle Marek-Spartz
-
Mike Meyer
-
Tobias Dammers
-
Tobias Florek