| > Do those you mention handle content type and encodings correctly? I honestly can't say for sure, but I've never encountered such a problem in my own usage. Maybe that just means I've been lucky. I just know from firsthand experience that they do a lot of things better than the HTTP package does. > The main problem is the need to use "toValue" and "toHtml" all the time. I guess I don't understand why the element building functions don't accept strings. First of all, if you're writing string literals and explicitly converting them with `toHtml`, you're missing out. Instead, enable the OverloadedStrings extension, and then you can do this sort of thing: html $ do
head $ title "My Web Page"
body $ do
h1 "A Heading"
h2 "A Subheading"
hr
p "A paragraph of text"
p $ "Another paragraph, with an " <> (a ! href "http://example.com/") "embedded link"
p $ em "Emphasized text" <> " and " <> strong "strongly emphasized text"
Notice the total lack of `toHtml` there.The HTML DSL functions don't accept strings because String and Html are two fundamentally different types of data. Enabling the type system to differentiate between the two lets you do some pretty nifty things. For instance, if you were to write "<script>alert('XSS!');</script>" :: String
you'd be in trouble, but you can't do that since blaze-html doesn't accept plain old strings. Instead, you'd write "<script>alert('XSS!');</script>" :: Html
Note how only the type is changed, but now, the string will be transparently converted to "<script>alert('XSS!');</script>" before it's added to the document, and thus you're safe, without having to actually do anything different. The type signatures I gave are superfluous of course, since they'd be inferred automatically. The type system makes this kind of flaw impossible.Plus, since blaze combinators are just Haskell, and the Html type is a monad, you can use all the usual Monad functions with Html: ol $ mapM_ (li . toHtml) ['A'..'Z']
That generates a 26-item list of letters from A to Z. Yes, you do have to do the explicit conversion to Html there, but I think that's a small price to pay for all the flexibility afforded by templating HTML with full-fledged Haskell code.> But for templating, I just don't like embedding templates in the actual source code of the HTTP verb it's for. The main controller code should be about preparing data for the UI, and the UI should be separate from the controller code. You could put it in a separate file and function and import it, of course, but it's still Haskell code, which must be compiled along with the entire app, which slows down the development cycle a lot. Yeah, I just put "view code" like the above examples into a separate module and import it. I don't find the slowdown to be significant, but maybe that's just me. In any case, true template languages have to be compiled too, either with the rest of the program or at runtime, so one way or another you incur that cost no matter what you're using. > I haven't looked closely at the various web frameworks to see if they support Rails-style reloading (ie., recompiling and reloading the app on each page load). Do you know? Yesod does this by default, and Snap can, if you use `snap-loader-dynamic` for your development builds. I believe they both use the awesome `hint` package for runtime eval and compilation of Haskell code. I don't think Happstack has any auto-reloading capability though. > Why invent something that looks like HTML but isn't? HAML syntax is basically (almost) CSS selectors, that's the whole point. And again, it's apparently meant to be placed inline. It doesn't seem that different from HAML to me, but it's clearly a subjective judgment. :) And it doesn't have to be inline. It uses the QuasiQuotes language extension, which means you can do inline snippets or write it in a separate file, however you like. Hamlet, Cassius, Lucius, and Julius (collectively, the "Shakespearean" template languages) are developed by the Yesod framework guys, not Snap, by the way. Snap uses a template language called Heist by default, which I don't particularly care for (I just use blaze-html instead). > Oh, interesting. I don't know about MonadIO yet. Will definitely read up on this. If you use liftIO, you're using MonadIO. That's what liftIO does, it's an adapter between plain IO values and polymorphic MonadIO values. But if library authors use MonadIO instead of IO, you can omit the explicit conversion. This isn't something you really have control over as the user of a library though. > With more complex libraries, the machine-generated docs become increasingly obtuse. For example, I would never, ever have figured out how to use HXT with Hackage alone. I mean, look at it! Fully agreed. HXT is a huge, complex beast! I don't think it's fair to judge all libraries by that standard, though. HXT is clearly at an extreme end of that continuum. |
I appreciate the input on the other things. I will check out Snap, I think.