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 <tdammers@gmail.com>:
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 <haskell@ibotty.net> 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.objoriented.html

> _______________________________________________
> 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.