[web-devel] Hoogle Advice

Jeremy Shaw jeremy at n-heptane.com
Tue Jan 25 18:14:50 CET 2011


On Jan 24, 2011, at 11:54 PM, Michael Snoyman wrote:

> * They are writing a site that involves very few of the features
> offered by a framework. For example, no routing, no persistence, no
> templating. In such a case, it's likely that a framework will simply
> get in their way.

Yes. I think that is a pretty small subset of web applications?

> * Haskellers tend to be an "opinionated" bunch, so it's not surprising
> that any random Haskeller may disagree with the design decisions of
> specific frameworks.

I think that many random Haskellers start by assuming their ideas are  
better than everyone else's and don't even look to see if they  
disagree with the decisions of specific frameworks :p

> Can you honestly tell me that you think Happstack is that right tool
> for every site?

Not for every site. But possibly for every site that Neil is going to  
be working on. Many of his 'complaints' about WAI are things which are  
addressed by Happstack to some degree:

1. statusOK vs status200 - happstack offers combinators like, ok,  
notFound, seeOther, unauthorized, etc. and a function 'resp' for  
setting the response code explicitly.

  2. predefined list of headers like "content-type" - happstack  
includes many constants an Handler.hs (they could be exposed better  
though)

  3. what happens when using 'ResponseFile' but the file is not found  
- happstack's documentation says what happens when serveFile or  
serveDirectory does not find the file

  4. exception handling -- the happstack docs show how to integrate  
exception catching and handling into your ServerPartT (though they  
could be more explicit about what happens to uncatch exceptions)

  5. happstack-server currently supports lazy IO natively and should  
be a good match

  6. happstack has a showResponse function for debugging

  7. the ServerPartT monad has a built-in FilterT monad which makes it  
easy to apply a function (Response -> Response) to modify the response.

  8. killing the running background threads in GHCi is really tricky.  
You need to basically track all the forkIO calls and save the  
threadIds so that you can come back and kill them  later when you get  
Crtl+C. But, happstack does have support for doing that :) Also, the  
waitForTermination function that happstack provides also has support  
for Windows.

So, given the fact that all the points Neil raised regarding WAI are  
addressed to some degree already in Happstack -- it seems like working  
with Happstack would not be a bad thing..

> That's one of the main reasons I've designed Yesod and WAI the way I
> have. By splitting the project up into so many pieces (Hamlet,
> Persistent, authenticate, etc), users get to pick and choose exactly
> what they want.

Yes. Happstack is the same way.

> It's very likely that Neil may end up reinventing a lot of the
> features of a framework in this Hoogle project. But I *still* think
> this is a good thing:

Based on my familiarity with Neil's previous work on things like  
catch, super-o, and other projects, I am interested to see what he  
comes up with as well. He has a tendency to address important issues  
that other people have swept under the rug.

> * And even if none of that happens, it probably took him less time to
> rewrite the features he needed than go through either the Happstack or
> Yesod tutorials. For someone developing lots of sites, the learning
> curve is IMO worth it; for a one-off project, I doubt it is.

I highly doubt that. It can't take more than an hour or two to go  
through the happstack tutorial. What I do think is true is that:

  1. writing code is satisfying and feels productive
  2. reading documentation is boring and doesn't feel productive
  3. most programmers assume their code is like a  beautiful flower,  
and that everyone else's is a putrid swamp of sewage.

And hence they are happy to spend days reinventing something rather  
than spend an hour reading about an existing solution :p (This is not  
directed at Neil who actually asked for advice about what already  
existed. Though he may still feel that Happstack is a putrid swamp of  
sewage...)

> * If he is so inclined, he could release this "boilerplate" code into
> a separate package and, walla, we have a *new* Haskell framework,
> building on top of what we have already, that caters to a new
> audience.


Or, maybe it just reimplements what we already have with minor  
cosmetic differences, weaknesses compared to other frameworks due to  
have less real world usage, and a few improvements which could have  
been more easily added to existing frameworks.

For example, let's consider what a framework is likely going to have  
for it's monad. For starters you are going to want easy access to the  
Request. So you'll have something like this:

 > type FrameworkT = ReaderT Request m a

Then you'll realize you need some way to escape things early and  
return an error, so you might add the ErrorT monad transformer so you  
have a way to escape and return a Response.

 > type FrameworkT = ReaderT Request (ErrorT Response m) a

Then you'll realize you need some way to modify the Responses to do  
things like add extra headers (for cookies, etc) or compress the  
Response, or whatever. So you might had a StateT that can hold filters  
to apply:

 > type FrameworkT = ReaderT Request (ErrorT Response (StateT  
(Response -> Response) m)) a
 >
 > setFilter :: (Response -> Response) -> FrameworkT m a
 > appendFilter :: (Response -> Response) -> FrameworkT m a

And then you might decide that you want your FrameworkT monad to be an  
instance of MonadPlus, so you add in MaybeT:

 > type FrameworkT = ReaderT Request (ErrorT Response (StateT  
(Response -> Response) (MaybeT m))) a

And now you have created a new Framework monad that looks suspiciously  
like the ones that already exist in other frameworks. Happstack, Snap,  
and Yesod all have variations on this basic theme. For example, in  
Yesod it appears you ultimately came up with,

type GHInner s m =
     ReaderT (HandlerData s m) (
     MEitherT HandlerContents (
     WriterT (Endo [Header]) (
     StateT SessionMap ( -- session
     IO
     ))))
:p

We don't really need anyone to reinvent another variation of this out  
of ignorance. They should either blatantly rip it off, or tell us why  
it is wrong and come up with something better :p

> I don't like seeing a fractured community, but I think this is exactly
> the opposite effect: we're seeing new levels of integration of
> pre-existing tools than we saw before.

Oh ?

Anyway, I am not against the development of new frameworks. But I  
think it would be better if people started new frameworks because they  
have discovered why the current ones are fundamentally broken, rather  
than just assuming they are and then reinventing the same thing :)  
But, in practice, people are going to keep reinventing the wheel, so  
I'll just keep my eye on them and steal the good parts ;)

- jeremy

p.s. Nothing in this message is intended to be a personal attack on  
anyone specific. It more reflects years of hearing people say, "Oh I  
didn't realize happstack already could do that."

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/web-devel/attachments/20110125/1e00d5ea/attachment.htm>


More information about the web-devel mailing list