<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-3300386911011555799</id><updated>2012-02-01T13:16:02.915-06:00</updated><category term='hsx'/><category term='type-safe'/><category term='jmacro'/><category term='persistence'/><category term='happstack-lite'/><category term='templating'/><category term='routing'/><category term='ANN'/><category term='safecopy'/><category term='web-routes'/><category term='happstack'/><category term='MACID'/><category term='acid-state'/><category term='database'/><title type='text'>Happstack</title><subtitle type='html'>Happstack - A Haskell Web Framework</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-2031597399626122650</id><published>2012-02-01T13:16:00.000-06:00</published><updated>2012-02-01T13:16:02.928-06:00</updated><title type='text'>new tutorial on acid-state, ixset, and lenses</title><content type='html'>Hello,&lt;br /&gt;&lt;br /&gt;I just uploaded a new tutorial which covers three distinct, but related topics:&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;acid-state - a native Haskell, noSQL, RAM-cloud database&lt;/li&gt;&lt;li&gt;IxSet &amp;nbsp;- a multi-indexed collection type (similar to Data.Map but with support for &amp;nbsp;multiple keys)&lt;/li&gt;&lt;li&gt;data-lens - a library which provides syntax that makes it easier to update nested records and other data types&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The tutorial is available here:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://happstack.com/docs/crashcourse/AcidState.html"&gt;http://happstack.com/docs/crashcourse/AcidState.html&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The section on lenses is a great applied introduction to the concept which requires no understanding of Happstack, acid-state, or IxSet. So, even if you don't care about acid-state, you may find it useful if you have ever wondered what the heck lenses are.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-2031597399626122650?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/2031597399626122650/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2012/02/new-tutorial-on-acid-state-ixset-and.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/2031597399626122650'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/2031597399626122650'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2012/02/new-tutorial-on-acid-state-ixset-and.html' title='new tutorial on acid-state, ixset, and lenses'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-8258406287870280745</id><published>2012-01-22T19:00:00.000-06:00</published><updated>2012-01-22T19:01:40.216-06:00</updated><title type='text'>ANN: happstack-server 6.5.1</title><content type='html'>I am pleased to announce the release of happstack-server 6.5.1. Changes include:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;ul&gt;&lt;li&gt;support for https:// (aka, SSL/TLS)&amp;nbsp;&lt;a href="https://groups.google.com/group/happs/browse_thread/thread/d92c24a7a81adfe8"&gt;https://groups.google.com/group/happs/browse_thread/thread/d92c24a7a81adfe8&lt;/a&gt;&lt;/li&gt;&lt;li&gt;directory listings now sorted in alphabetical order&lt;/li&gt;&lt;li&gt;added Happstack class instances for ReaderT, WriterT, StateT, and RWST&lt;/li&gt;&lt;li&gt;happstack-server now compiles without producing any warnings&lt;/li&gt;&lt;li&gt;various code cleanup and formatting&lt;/li&gt;&lt;/ul&gt;&lt;div&gt;Discussion here:&amp;nbsp;&lt;/div&gt;&lt;div&gt;&lt;a href="http://www.reddit.com/r/haskell/comments/os5kb/ann_happstackserver_651_https_aka_ssltls_support/"&gt;http://www.reddit.com/r/haskell/comments/os5kb/ann_happstackserver_651_https_aka_ssltls_support/&lt;/a&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-8258406287870280745?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/8258406287870280745/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2012/01/ann-happstack-server-651.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8258406287870280745'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8258406287870280745'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2012/01/ann-happstack-server-651.html' title='ANN: happstack-server 6.5.1'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-8070578174375527653</id><published>2012-01-14T11:35:00.002-06:00</published><updated>2012-01-14T11:37:19.738-06:00</updated><title type='text'>happstack.com: now less evil</title><content type='html'>If you experienced some outage today trying to reach happstack.com, it is because we very ungracefully transfered our domain from the evil pro-SOPA godaddy to the less-evil anti-SOPA namecheap. Yay!&lt;br /&gt;&lt;br /&gt;You are probably already familiar with SOPA/PIPA, but if not, here is some more information:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://lifehacker.com/5860205/all-about-sopa-the-bill-thats-going-to-cripple-your-internet"&gt;http://lifehacker.com/5860205/all-about-sopa-the-bill-thats-going-to-cripple-your-internet&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;The DNS changes have probably propagated to you by now, but if not, they should in the next 24 hours.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-8070578174375527653?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/8070578174375527653/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2012/01/happstackcom-now-less-evil.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8070578174375527653'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8070578174375527653'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2012/01/happstackcom-now-less-evil.html' title='happstack.com: now less evil'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-8475502057536940595</id><published>2011-11-14T20:23:00.001-06:00</published><updated>2011-11-14T20:28:01.328-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='happstack-lite'/><category scheme='http://www.blogger.com/atom/ns#' term='happstack'/><category scheme='http://www.blogger.com/atom/ns#' term='ANN'/><title type='text'>ANN: happstack-lite - a friendly introduction to Happstack</title><content type='html'>&lt;br /&gt;Happstack is a powerful Haskell web framework with a rich API that has&lt;br /&gt;evolved over the last 7 years to meet the needs of real world web&lt;br /&gt;development.&lt;br /&gt;&lt;br /&gt;Unfortunately a rich and flexible API can also be daunting when all&lt;br /&gt;you need is something simple. What many people don't realize is that&lt;br /&gt;inside Happstack lives a very simple and easy to use web framework.&lt;br /&gt;&lt;br /&gt;I am pleased to announce a new member of the Happstack family:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://happstack.com/docs/happstack-lite/happstack-lite.html"&gt;happstack-lite&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;happstack-lite is minimal version of Happstack that is designed give&lt;br /&gt;you everything you need to get started with web develop in a much&lt;br /&gt;cleaner, easier package. It is an ideal starting point for novice Haskell programmers or developers who are new to the Happstack family.&lt;br /&gt;&lt;br /&gt;We have done that by:&lt;br /&gt;&lt;br /&gt;&amp;nbsp;1. collecting the most essential types and functions into a single, well-documented module&lt;br /&gt;&lt;br /&gt;&amp;nbsp;2. giving all the functions simple type signatures. No crazy monad&lt;br /&gt;&amp;nbsp;transformers, far fewer type classes, etc.&lt;br /&gt;&lt;br /&gt;&amp;nbsp;3. creating a new, small tutorial (less than 2000 words) that shows&lt;br /&gt;&amp;nbsp;you how to use all the features of happstack-lite.&lt;br /&gt;&lt;br /&gt;But, the best part is that happstack-lite is 100% compatible with regular Happstack. If you find you do need some of the extra features that Happstack offers, you can simply import the extra functions and use them. Migrating from happstack-lite to happstack is trivial -- mostly just changing `import Happstack.Lite` to `import Happstack.Server`. So, you are not locked into staying with happstack-lite if you decide you need more. And you can still use the many addon packages such as happstack-hsp or happstack-jmacro if you want.&lt;br /&gt;&lt;br /&gt;happstack-lite is not crippled or underpowered. In fact, it offers features and performance on par with other Haskell frameworks while being as simple as possible. If you have ever looked at Happstack in the past and felt it was too complicated -- I would highly encourage to look again. Especially if the last time you looked was prior to Happstack 6.&lt;br /&gt;&lt;br /&gt;Check out the tutorial here: &lt;a href="http://happstack.com/docs/happstack-lite/happstack-lite.html"&gt;happstack-lite&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;We would love to hear your feedback and criticisms. Please see the related discussion at:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.reddit.com/r/haskell/comments/mcjoz/ann_happstacklite_a_simpler_friendlier_version_of/" target="_blank"&gt;http://www.reddit.com/r/haskell&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-8475502057536940595?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/8475502057536940595/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2011/11/ann-happstack-lite-friendly.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8475502057536940595'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8475502057536940595'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2011/11/ann-happstack-lite-friendly.html' title='ANN: happstack-lite - a friendly introduction to Happstack'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-7913904142634581730</id><published>2011-07-21T13:18:00.000-05:00</published><updated>2011-12-10T11:03:50.155-06:00</updated><title type='text'>type-safe urls via web-routes, part 2: Boomerang</title><content type='html'>&lt;kbd&gt;web-routes&lt;/kbd&gt; is a system for implementing type-safe web-routes in Haskell web applications.  In &lt;a href="http://happstack.blogspot.com/2011/07/type-safe-urls-via-web-parts-part-1.html"&gt;part 1&lt;/a&gt;, we saw the basics of how to use web-routes.&lt;br /&gt;&lt;br /&gt;In part 1, we used template haskell to automatically derive the mapping between the url string and the url type. This makes development very easy, but the automatically derived urls are not all that visually appealing.&lt;br /&gt;&lt;br /&gt;In this part, we introduce a way to manually specify the mapping between the url type and the url string. This gives the developer 100% control over the mapping. Up to now, the problem with creating a manual mapping has been that you had to implement the specification twice. You had to write a show function to turn a url type into a url string, and a read function to turn a url string into a url type.   These functions are basically inverses of each other, both following the same spec. &lt;br /&gt;&lt;br /&gt;What we really want to do is write the spec once and automatically extract the printer and parser from the spec. That way we can be sure they are inverses of each other, and we do not have to repeat ourselves. And we do not have to repeat ourselves. Because that is annoying.&lt;br /&gt;&lt;br /&gt;Fortunately, Sjoerd Visscher and Martijn van Steenbergen figured out exactly how to do that and published a proof of concept library know as &lt;a href="http://hackage.haskell.org/package/Zwaluw"&gt;&lt;kbd&gt;Zwaluw&lt;/kbd&gt;&lt;/a&gt;. With permission, I have refactored their original library into two separate libraries: &lt;a href="http://hackage.haskell.org/package/boomerang"&gt;&lt;kbd&gt;boomerang&lt;/kbd&gt;&lt;/a&gt; and &lt;a href="http://hackage.haskell.org/package/web-routes-boomerang"&gt;&lt;kbd&gt;web-routes-boomerang&lt;/kbd&gt;&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;&lt;kbd&gt;boomerang&lt;/kbd&gt; is a general purpose, standalone invertible parser library. &lt;kbd&gt;web-routes-boomerang&lt;/kbd&gt; adds glue code around &lt;kbd&gt;boomerang&lt;/kbd&gt; so that it can be used to with &lt;kbd&gt;web-routes&lt;/kbd&gt;.&lt;br /&gt;&lt;br /&gt;Using &lt;kbd&gt;boomerang&lt;/kbd&gt; we can take a route like this one:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt; &lt;span class="hs-keyword"&gt;data&lt;/span&gt; &lt;span class="hs-conid"&gt;Sitemap&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-keyglyph"&gt;=&lt;/span&gt; &lt;span class="hs-conid"&gt;Home&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-keyglyph"&gt;|&lt;/span&gt; &lt;span class="hs-conid"&gt;Article&lt;/span&gt; &lt;span class="hs-conid"&gt;ArticleId&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-keyglyph"&gt;|&lt;/span&gt; &lt;span class="hs-conid"&gt;UserOverview&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-keyglyph"&gt;|&lt;/span&gt; &lt;span class="hs-conid"&gt;UserDetail&lt;/span&gt; &lt;span class="hs-conid"&gt;Int&lt;/span&gt; &lt;span class="hs-conid"&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;       &lt;span class="hs-keyword"&gt;deriving&lt;/span&gt; &lt;span class="hs-layout"&gt;(&lt;/span&gt;&lt;span class="hs-conid"&gt;Eq&lt;/span&gt;&lt;span class="hs-layout"&gt;,&lt;/span&gt; &lt;span class="hs-conid"&gt;Ord&lt;/span&gt;&lt;span class="hs-layout"&gt;,&lt;/span&gt; &lt;span class="hs-conid"&gt;Read&lt;/span&gt;&lt;span class="hs-layout"&gt;,&lt;/span&gt; &lt;span class="hs-conid"&gt;Show&lt;/span&gt;&lt;span class="hs-layout"&gt;,&lt;/span&gt; &lt;span class="hs-conid"&gt;Data&lt;/span&gt;&lt;span class="hs-layout"&gt;,&lt;/span&gt; &lt;span class="hs-conid"&gt;Typeable&lt;/span&gt;&lt;span class="hs-layout"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;a specify a route map like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt; &lt;span class="hs-definition"&gt;sitemap&lt;/span&gt; &lt;span class="hs-keyglyph"&gt;::&lt;/span&gt; &lt;span class="hs-conid"&gt;Router&lt;/span&gt; &lt;span class="hs-conid"&gt;Sitemap&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt; &lt;span class="hs-definition"&gt;sitemap&lt;/span&gt; &lt;span class="hs-keyglyph"&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-layout"&gt;(&lt;/span&gt;  &lt;span class="hs-varid"&gt;rHome&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-varop"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="hs-varid"&gt;rArticle&lt;/span&gt; &lt;span class="hs-varop"&gt;.&lt;/span&gt; &lt;span class="hs-layout"&gt;(&lt;/span&gt;&lt;span class="hs-varid"&gt;lit&lt;/span&gt; &lt;span class="hs-str"&gt;"article"&lt;/span&gt; &lt;span class="hs-varop"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; &lt;span class="hs-varid"&gt;articleId&lt;/span&gt;&lt;span class="hs-layout"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-varop"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="hs-varid"&gt;lit&lt;/span&gt; &lt;span class="hs-str"&gt;"users"&lt;/span&gt; &lt;span class="hs-varop"&gt;.&lt;/span&gt; &lt;span class="hs-varid"&gt;users&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-layout"&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;     &lt;span class="hs-keyword"&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;       &lt;span class="hs-varid"&gt;users&lt;/span&gt; &lt;span class="hs-keyglyph"&gt;=&lt;/span&gt;  &lt;span class="hs-varid"&gt;rUserOverview&lt;/span&gt;&lt;br /&gt;&lt;span class="hs-varop"&gt;&amp;gt;&lt;/span&gt;             &lt;span class="hs-varop"&gt;&amp;lt;&amp;gt;&lt;/span&gt; &lt;span class="hs-varid"&gt;rUserDetail&lt;/span&gt; &lt;span class="hs-varop"&gt;&amp;lt;/&amp;gt;&lt;/span&gt; &lt;span class="hs-varid"&gt;int&lt;/span&gt; &lt;span class="hs-varop"&gt;.&lt;/span&gt; &lt;span class="hs-varid"&gt;lit&lt;/span&gt; &lt;span class="hs-str"&gt;"-"&lt;/span&gt; &lt;span class="hs-varop"&gt;.&lt;/span&gt; &lt;span class="hs-varid"&gt;anyString&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;which defines a mapping like this:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;table&gt; &lt;thead&gt;&lt;tr&gt;&lt;th&gt;url&lt;/th&gt;&lt;th&gt;&lt;/th&gt;&lt;th&gt;type&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt; &lt;tbody&gt;&lt;tr&gt;&lt;td&gt;/&lt;/td&gt;&lt;td&gt;&amp;lt;=&amp;gt;&lt;/td&gt;&lt;td&gt;Home&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/article/&lt;i&gt;int&lt;/i&gt;&lt;/td&gt;&lt;td&gt;&amp;lt;=&amp;gt;&lt;/td&gt;&lt;td&gt;Article &lt;i&gt;int&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/users&lt;/td&gt;&lt;td&gt;&amp;lt;=&amp;gt;&lt;/td&gt;&lt;td&gt;UserOverview&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;/users/&lt;i&gt;int&lt;/i&gt;-&lt;i&gt;string&lt;/i&gt;&lt;/td&gt;&lt;td&gt;&amp;lt;=&amp;gt;&lt;/td&gt;&lt;td&gt;UserDetail &lt;i&gt;int&lt;/i&gt; &lt;i&gt;string&lt;/i&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;br /&gt;The &lt;kbd&gt;sitemap&lt;/kbd&gt; function looks like a ordinary parser. But, what makes it is exciting is that it also defines the pretty-printer at the same time.&lt;br /&gt;&lt;br /&gt;For more in-depth details, see the &lt;a href="http://happstack.com/docs/crashcourse/WebRoutes.html#web-routes-boomerang"&gt;relevant section&lt;/a&gt; of the Happstack Crash Course. If you just want to play with &lt;kbd&gt;boomerang&lt;/kbd&gt; then &lt;a href="http://hackage.haskell.org/packages/archive/boomerang/1.0.0/doc/html/Text-Boomerang.html"&gt;start here&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-7913904142634581730?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/7913904142634581730/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2011/07/type-safe-urls-via-web-parts-part-2_21.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/7913904142634581730'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/7913904142634581730'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2011/07/type-safe-urls-via-web-parts-part-2_21.html' title='type-safe urls via web-routes, part 2: Boomerang'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-2323697880974906321</id><published>2011-07-11T15:14:00.000-05:00</published><updated>2011-12-10T11:03:38.529-06:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='type-safe'/><category scheme='http://www.blogger.com/atom/ns#' term='routing'/><category scheme='http://www.blogger.com/atom/ns#' term='web-routes'/><title type='text'>type-safe urls via web-routes, part 1</title><content type='html'>web-routes is a suite of libraries which provide "type-safe" web routing. Instead of working directly with url strings in your web application, you create types to represent the routes.&lt;br /&gt;&lt;br /&gt;The web-routes library has been around for several years. The idea itself is fairly obvious to many Haskell programmers, and so the idea has been rediscovered many times. &lt;br /&gt;&lt;br /&gt;web-routes is designed to be exceedingly flexible. It is not explicitly tied to any haskell web framework, templating system, etc. It forms the basis of type-safe urls in yesod. There is also support for Happstack and HSP. &lt;br /&gt;&lt;br /&gt;web-routes does not impose any particular method of mapping the url types to strings. We provide a variety of ways to defining mappings via addons including quasi-quotation, template haskell, generics, parsec, and more. If none of these systems suit your fancy, you can easily provide your own system. You basically need to provide two functions:&lt;br /&gt;&lt;br /&gt;&lt;code&gt;urlToString :: url -&amp;gt; [(String, String)] -&amp;gt; [String]&lt;/code&gt;&lt;br /&gt;&lt;code&gt;stringToUrl :: [String] -&amp;gt; Either String url&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;If you have an idea for how to map urls to types, I would encourage you to consider basing it on web-routes. A significant amount of effort has gone into handling issues like unicode and url escaping (among other things). If you use web-routes you do not need to know *any* of those rules. web-routes takes care of all that nastiness for you. If you find that web-routes is not suitable for your needs, I would love to hear why and see if we can not fix it.&lt;br /&gt;&lt;br /&gt;The biggest issue with web-routes has been the lack of good documentation. So, I am pleased to announce that the first in a series of tutorials on web-routes is now online at: &lt;a href="http://happstack.com/docs/crashcourse/WebRoutes.html"&gt;http://happstack.com/docs/crashcourse/WebRoutes.html&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Comments, questions, and corrections appreciated!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-2323697880974906321?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/2323697880974906321/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2011/07/type-safe-urls-via-web-parts-part-1.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/2323697880974906321'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/2323697880974906321'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2011/07/type-safe-urls-via-web-parts-part-1.html' title='type-safe urls via web-routes, part 1'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-4313204940923365259</id><published>2011-05-23T15:22:00.000-05:00</published><updated>2011-05-23T15:22:29.979-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='happstack'/><category scheme='http://www.blogger.com/atom/ns#' term='templating'/><category scheme='http://www.blogger.com/atom/ns#' term='jmacro'/><category scheme='http://www.blogger.com/atom/ns#' term='hsx'/><title type='text'>Happstack + JMacro + HSX</title><content type='html'>&lt;a href="http://www.happstack.com/"&gt;Happstack&lt;/a&gt; (a Haskell web framework) has long had support for using HSX so that you can use XML syntax in your Haskell page templates. Happstack now has support for using &lt;a href="http://www.haskell.org/haskellwiki/Jmacro"&gt;JMacro&lt;/a&gt; to add javascript to your templates.&lt;br /&gt;&lt;br /&gt;JMacro was written by Gershom Bazerman, and was first released in July of 2009. Our contribution is the creation of two glue libraries:&lt;br /&gt;&lt;dl&gt; &lt;dt&gt;&lt;a href="http://hackage.haskell.org/package/hsx-jmacro-6.0.1"&gt;hsx-jmacro&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;a thin wrapper which makes it easy to embed JMacro into HSX (independent of Happstack).&lt;/dd&gt; &lt;dt&gt;&lt;a href="http://hackage.haskell.org/package/happstack-jmacro-6.0.0"&gt;happstack-jmacro&lt;/a&gt;&lt;/dt&gt;&lt;dd&gt;another thin wrapper that makes it easy to generate and serve JMacro .js scripts using Happstack&lt;/dd&gt;&lt;/dl&gt;&lt;br /&gt;The use of Happstack+HSX+JMacro has been documented in detail in &lt;a href="http://happstack.com/docs/crashcourse/Templates.html#jmacro"&gt;this section&lt;/a&gt; of the Happstack Crash Course.&lt;br /&gt;&lt;br /&gt;Here is a little example of what Happstack+HSX+JMacro looks like:&lt;br /&gt;&lt;div class="code"&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloJMacro&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;JMacroPart&lt;/span&gt; &lt;span class='hs-conid'&gt;Response&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloJMacro&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-varid'&gt;toResponse&lt;/span&gt; &lt;span class='hs-varop'&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;defaultTemplate&lt;/span&gt; &lt;span class='hs-str'&gt;"Hello JMacro"&lt;/span&gt; &lt;span class='hs-conid'&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;       &lt;span class='hs-varop'&gt;&amp;lt;&lt;/span&gt;&lt;span class='hs-varid'&gt;div&lt;/span&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;        &lt;span class='hs-varop'&gt;&amp;lt;%&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-varop'&gt;$&lt;/span&gt;&lt;span class='hs-varid'&gt;jmacro&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;|&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;            &lt;span class='hs-varid'&gt;var&lt;/span&gt; &lt;span class='hs-varid'&gt;helloNode&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;document&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;createElement&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-chr'&gt;'&lt;/span&gt;&lt;span class='hs-varid'&gt;h1'&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;            &lt;span class='hs-varid'&gt;helloNode&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;appendChild&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;document&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;createTextNode&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-str'&gt;"Hello, JMacro!"&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;            &lt;span class='hs-varid'&gt;document&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;body&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;appendChild&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;helloNode&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;            &lt;span class='hs-keyglyph'&gt;|&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt; &lt;span class='hs-varop'&gt;%&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;       &lt;span class='hs-varop'&gt;&amp;lt;/&lt;/span&gt;&lt;span class='hs-varid'&gt;div&lt;/span&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;As you can see, the syntax used by JMacro is almost identical to JavaScript. So, you do not have to learn some special DSL to use it. In fact, JMacro can work with most JavaScript you find in the wild. Using JMacro has a number of advantages over just using plain-old javascript:&lt;br /&gt;&lt;ul&gt; &lt;li&gt;syntax checking ensures that your JavaScript is syntactically valid at compile time. That eliminates many common JavaScript errors and reduces development time.&lt;/li&gt; &lt;li&gt;hygienic names and scoping automatically and transparently ensure that blocks of JavaScript code do not accidentally create variables and functions with conflicting names.&lt;/li&gt; &lt;li&gt;Antiquotation, marshalling, and shared scope make it easy to splice Haskell values into the JavaScript code. It also makes it easy to programmatically generate JavaScript code.&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;The last point means that instead of trying to concat strings to call JavaScript functions with Haskell values like this:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;hello str = &amp;lt;button onclick=("alert(" ++ str ++ ");")&amp;gt;click me&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;You can write:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;hello str = &amp;lt;button onclick=[$jmacro| alert(`(str)`); |]&amp;gt;click me&amp;lt;/button&amp;gt;&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;The first version has a major bug -- it does not properly escape the &lt;code&gt;str&lt;/code&gt; which can lead to javascript injection attacks.  The JMacro version, on the other hand, automatically escapes the string.&lt;br /&gt;&lt;br /&gt;You are not limited to just splicing strings and other primitive types into the JavaScript code. By creating an instance of &lt;code&gt;ToJExpr&lt;/code&gt; you can easily pass any Haskell value to JavaScript.&lt;br /&gt;&lt;br /&gt;While JMacro can easily be used for simple templating, it is actually a very powerful tool for generating JavaScript. It is essentially Template Haskell for JavaScript. It parses the JavaScript into an abstract syntax tree, and supports quasiquotation and antiquotation.&lt;br /&gt;&lt;br /&gt;To learn more about using JMacro with Happstack and HSX, start &lt;a href="http://happstack.com/docs/crashcourse/Templates.html#jmacro"&gt;reading here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;And a big thanks for Gershom Bazerman for creating JMacro. It's not part of Happstack or HSX, so you should have no problems using it with other web frameworks or templating libraries.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-4313204940923365259?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/4313204940923365259/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2011/05/happstack-jmacro-hsx.html#comment-form' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/4313204940923365259'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/4313204940923365259'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2011/05/happstack-jmacro-hsx.html' title='Happstack + JMacro + HSX'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-5298738546125282604</id><published>2011-05-02T13:18:00.001-05:00</published><updated>2011-05-02T15:21:08.059-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='safecopy'/><category scheme='http://www.blogger.com/atom/ns#' term='persistence'/><category scheme='http://www.blogger.com/atom/ns#' term='acid-state'/><category scheme='http://www.blogger.com/atom/ns#' term='MACID'/><category scheme='http://www.blogger.com/atom/ns#' term='database'/><title type='text'>MACID Haskell persistent data store overhauled</title><content type='html'>Over the past few weeks Lemmih has been working on a major overhaul of MACID. MACID is a persistent data store explicitly designed for use with Haskell. It can store arbitrary Haskell data structures and queries are written in straight-forward Haskell (no funky DSLs). It is thread-safe, and supports the classic ACID properties. Unplug your machine with out losing your data. &lt;br /&gt;&lt;br /&gt;The homepage for the new MACID library can be found &lt;a href="http://acid-state.seize.it/"&gt;here.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;There are two new libraries acid-state and safecopy, which will replace happstack-data and happstack-state in Happstack 7.&lt;br /&gt;&lt;br /&gt;safecopy provides versioned binary serialization of datatypes with version migration. It adds this functionality on top of the cereal library. &lt;br /&gt;&lt;br /&gt;acid-state provides ACID transactions on top of safecopy.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;What's New&lt;/h3&gt;&lt;br /&gt;The new MACID is like the old MACID, but better. The fundamental concepts are the same, but it is a lot cleaner, more robust and less magical. &lt;br /&gt;&lt;br /&gt;The rewrite of MACID addresses many long standing wish-list items, including:&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;MACID now a separate project&lt;/h4&gt;&lt;br /&gt;acid-state and safecopy are now free standing libraries, with no references or dependencies on anything Happstack. They have their own maintainer, homepage, source repository, etc. So, now you can used MACID, even if you don't use Happstack. (This has actually been true for a while, but now it is a lot more obvious).&lt;br /&gt;&lt;br /&gt;If all you want is versioned binary serialization and migration, then you can use the safecopy library on its own.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;update / query take an explicit state handle now&lt;/h4&gt;&lt;br /&gt;In happstack-state, query and update accessed the state via a global IORef. This meant that you could only have one instance of MACID per application. It also weakened type-checking resulting runtime errors that should have been avoidable.&lt;br /&gt;&lt;br /&gt;It also meant that you could only have one ACID store per application.&lt;br /&gt;&lt;br /&gt;Now update and query take an explicit handle.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;No more Component class&lt;/h4&gt;&lt;br /&gt;happstack-state has a Component class, which is mostly worthless. It gives the promise of power, but doesn't really deliver anything. It is just extra boilerplate for the most part. This class is gone entirely in acid-state.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Less boilerplate for serialization instances&lt;/h4&gt;&lt;br /&gt;In happstack-data, creating a Serialization instance for a type required you to call &lt;code&gt;$(deriveSerialize ''Foo)&lt;/code&gt; and you have to create an &lt;code&gt;instance Version Foo&lt;/code&gt;. With safecopy, you only need one line, '$(deriveSafeCopy 0 'base ''Foo)'&lt;br /&gt;&lt;br /&gt;In happstack-data there were three type classes, &lt;code&gt;Serialize&lt;/code&gt;, &lt;code&gt;Version&lt;/code&gt;, and &lt;code&gt;Migrate&lt;/code&gt;. This has been simplified down to just two in safecopy: &lt;code&gt;SafeCopy&lt;/code&gt; and &lt;code&gt;Migrate&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Better Safety&lt;/h4&gt;&lt;br /&gt;happstack-state has a number of corner cases that it does not handle gracefully. For example, bad things happen if update events call fail or error. acid-state handles these correctly and includes a test suite specifically for testing these types of failures. &lt;br /&gt;&lt;br /&gt;Additionally, acid-state is a lot better at flushing data to disk.&lt;br /&gt;&lt;br /&gt;&lt;h4&gt;Performance&lt;/h4&gt;&lt;br /&gt;Initial performance testing shows that acid-state is fast. A simple data store that holds an integer which is incremented by an update event was able to achieve 13,300 updates per second.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Still Coming&lt;/h3&gt;&lt;br /&gt;There is still a bunch of work to come. &lt;br /&gt;&lt;br /&gt;acid-state currently does not support Windows. This is because the code to safely flush data to disk requires the posix library. Windows support can be added via some #ifdefs. If you are familiar with Windows and file IO and want to help, your contribution will be greatly appreciated.&lt;br /&gt;&lt;br /&gt;Migrating data from happstack-state to acid-state is certainly feasible, but the process is not yet documented. But it will be. &lt;br /&gt;&lt;br /&gt;There are also major improvements to IxSet planned.&lt;br /&gt;&lt;br /&gt;And, of course, replication and sharding. Fortunately, it will be easier to implement these on top of the new acid-state code base.&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;Get Started Today&lt;/h3&gt;&lt;br /&gt;acid-state is usable today! You can install it from hackage. There are code examples &lt;a href="http://mirror.seize.it/acid-state/examples/"&gt;here&lt;/a&gt; and &lt;a href="http://acid-state.seize.it/safecopy"&gt;here&lt;/a&gt;. If you are starting a new MACID based project, you are encouraged to consider acid-state.&lt;br /&gt;&lt;br /&gt;To use happstack-ixset you will currently need to add this extra instance to your code:&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Data&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;SafeCopy&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Data&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;            &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-keyword'&gt;qualified&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Data&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;  &lt;span class='hs-keyword'&gt;as&lt;/span&gt; &lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class='hs-keyword'&gt;instance&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;SafeCopy&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;Ord&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;Typeable&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Indexable&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;SafeCopy&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;IxSet&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyword'&gt;where&lt;/span&gt;&lt;br /&gt;    &lt;span class='hs-varid'&gt;putCopy&lt;/span&gt; &lt;span class='hs-varid'&gt;ixSet&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;contain&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;safePut&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;toList&lt;/span&gt; &lt;span class='hs-varid'&gt;ixSet&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;    &lt;span class='hs-varid'&gt;getCopy&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;contain&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-conid'&gt;IxSet&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;fromList&lt;/span&gt; &lt;span class='hs-varop'&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;safeGet&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Once IxSet is factored out of happstack into a separate library that instance will be provided automatically.&lt;br /&gt;&lt;br /&gt;It is safe to mix happstack-state and acid-state in the same application if you want to use acid-state in an existing application.&lt;br /&gt;&lt;br /&gt;More updates to come as things develop!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-5298738546125282604?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/5298738546125282604/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2011/05/macid-haskell-persistent-data-store.html#comment-form' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/5298738546125282604'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/5298738546125282604'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2011/05/macid-haskell-persistent-data-store.html' title='MACID Haskell persistent data store overhauled'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-3001696510052185742</id><published>2010-11-15T15:48:00.001-06:00</published><updated>2010-11-15T16:53:35.665-06:00</updated><title type='text'>ANN: happstack-heist now available</title><content type='html'>Thanks to cdsmith's &lt;a href="http://cdsmith.wordpress.com/2010/10/05/using-heist-and-happstack/"&gt;blog post&lt;/a&gt;, and Happstack's recent update to mtl-2, I am pleased to announce &lt;a href="http://hackage.haskell.org/package/happstack-heist"&gt;happstack-heist.&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Detailed documentation on using &lt;a href="http://happstack.com/docs/crashcourse/Templates.html#helloheist"&gt;Heist with Happstack&lt;/a&gt; is available in the Happstack Crash Course.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.happstack.com/"&gt;Happstack&lt;/a&gt; is a flexible Haskell Web Framework with many supporting optional components. &lt;br /&gt;&lt;br /&gt;Heist is an XML templating engine. The static portions of your templates are written in XML files which are loaded by the server at runtime. This makes it easy to modify the templates without having to recompile and restart the server. It also makes it easy to work with template designers who do not know Haskell.&lt;br /&gt;&lt;br /&gt;The dynamic portions of the templates are generated in Haskell and are spliced into the templates. This means you have the full expressive power of Haskell at your disposal for the generated portions of the templates. That is a lot nicer than trying to using something like XSLT (though Happstack does support that as well). &lt;br /&gt;&lt;br /&gt;Happstack offers a wide variety of templating solutions including BlazeHtml, HSP, Hamlet, and HStringTemplate. But Heist fills a nice hole in the spectrum, and we are pleased to be able to offer it now.&lt;br /&gt;&lt;br /&gt;It is available in darcs and on hackage. It has been tested against Happstack from darcs, but should work against Happstack stable as well.&lt;br /&gt;&lt;br /&gt;If there are any bugs or improvements you would like to see, let us know!&lt;br /&gt;&lt;br /&gt;- jeremy&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-3001696510052185742?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/3001696510052185742/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2010/11/ann-happstack-heist-now-in-darcs.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/3001696510052185742'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/3001696510052185742'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2010/11/ann-happstack-heist-now-in-darcs.html' title='ANN: happstack-heist now available'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-3323041215675504349</id><published>2010-10-20T20:55:00.000-05:00</published><updated>2010-10-20T21:37:58.021-05:00</updated><title type='text'>Recompile your Haskell-based templates faster than you can hit F5.</title><content type='html'>There are two main classes of templating solutions in Happstack:&lt;br /&gt;&lt;br /&gt; 1. DSLs/libraries such as BlazeHtml, HSP, Hamlet, etc, where your templates are written in Haskell and compiled at compile time.&lt;br /&gt;&lt;br /&gt; 2. Libraries like heist, HStringTemplate, etc, where your templates are written in some external template file and read at runtime by the server.&lt;br /&gt;&lt;br /&gt;Each method has strengths and weaknesses -- and so each project needs to pick the solution that works best for them.&lt;br /&gt;&lt;br /&gt;For my projects I love using HSP. I like having the full expressive power of Haskell in my templates, and the added safety that the type checker provides. But I &lt;i&gt;hate&lt;/i&gt; having to recompile, relink, and restart my app server dozens and dozens of times when I am developing my templates. And, so it is with great pleasure that I present the triumphant return of happstack-plugins!&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;happstack-plugins&lt;/h2&gt;&lt;br /&gt;happstack-plugins leverages the recently revived &lt;a href="http://hackage.haskell.org/package/plugins"&gt;plugins&lt;/a&gt; package so that individual page templates can be automatically recompiled and reloaded into a running happstack application. happstack-plugins uses hinotify to watch the haskell source files containing your page templates. Whenever you save changes, the page is automatically recompiled and reloaded into the running server. Typically this happens fast enough that by the time you switch to the browser and hit reload, the updated page is already available. &lt;br /&gt;&lt;br /&gt;You can see a demo of happstack-plugins in action here:&lt;br /&gt;&lt;br /&gt;&lt;object width="480" height="385"&gt;&lt;param name="movie" value="http://www.youtube.com/v/ok_gf0QVLnE?fs=1&amp;amp;hl=en_US"&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true"&gt;&lt;/param&gt;&lt;param name="allowscriptaccess" value="always"&gt;&lt;/param&gt;&lt;embed src="http://www.youtube.com/v/ok_gf0QVLnE?fs=1&amp;amp;hl=en_US" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="480" height="385"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;How to use happstack-plugins&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;Using happstack-plugins is very straight-forward. First you need to install the happstack-plugins library which is currently only available in the happstack darcs repository:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;darcs get http://patch-tag.com/r/mae/happstack&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;For best performance you should put each page template in its own module so that it can be recompiled and reloaded faster.&lt;br /&gt;&lt;br /&gt;The templates themselves require no special modifications. Here is a simple &lt;code&gt;helloPage&lt;/code&gt; template:&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;module&lt;/span&gt; &lt;span class='hs-conid'&gt;HelloPage&lt;/span&gt; &lt;span class='hs-keyword'&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPage&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;Response&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPage&lt;/span&gt; &lt;span class='hs-varid'&gt;noun&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;ok&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;toResponse&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-str'&gt;"hello, "&lt;/span&gt; &lt;span class='hs-varop'&gt;++&lt;/span&gt; &lt;span class='hs-varid'&gt;noun&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;This template takes a single String argument and returns a &lt;code&gt;text/plain&lt;/code&gt; page which says, "hello, &amp;lt;string&amp;gt;". We could just as well use BlazeHTML, HSP, etc, but using String keeps this example short and simple.&lt;br /&gt;&lt;br /&gt;As I mentioned, there is nothing new going on here, it just a normal happstack ServerPart.&lt;br /&gt;&lt;br /&gt;The interesting changes are in the Main module. There are only 3 simple changes required to support templates. But first, some boring stuff at the top of the module:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-comment'&gt;{-# LANGUAGE CPP, TemplateHaskell #-}&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;module&lt;/span&gt; &lt;span class='hs-conid'&gt;Main&lt;/span&gt; &lt;span class='hs-keyword'&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Control&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Monad&lt;/span&gt;     &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;msum&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt;  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;1. Here we #ifdef some module imports. These two modules provide the same interface. The Dynamic version actually does page recompilation and reloading. The Static version just links things in the normal way. This makes it easy to use dynamic loading during development but static linking for the live server by simply defining or undefining PLUGINS.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-cpp'&gt;#&lt;/span&gt;&lt;span class='hs-varid'&gt;ifdef&lt;/span&gt; &lt;span class='hs-conid'&gt;PLUGINS&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Plugins&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Dynamic&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-cpp'&gt;#&lt;/span&gt;&lt;span class='hs-keyword'&gt;else&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Plugins&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Static&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-cpp'&gt;#&lt;/span&gt;&lt;span class='hs-varid'&gt;endif&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;HelloPage&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;2. In main we call &lt;code&gt;initPlugins&lt;/code&gt; which starts the recompiler/reloader and hinotify. If you import &lt;code&gt;Happstack.Server.Plugins.Static&lt;/code&gt;, &lt;code&gt;initPlugins&lt;/code&gt; is a 'noop', so we do not have to add any extra &lt;code&gt;#ifdefs&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;IO&lt;/span&gt; &lt;span class='hs-conid'&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;    &lt;span class='hs-keyword'&gt;do&lt;/span&gt; &lt;span class='hs-varid'&gt;ph&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='hs-varid'&gt;initPlugins&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;       &lt;span class='hs-varid'&gt;simpleHTTP&lt;/span&gt; &lt;span class='hs-varid'&gt;nullConf&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;pages&lt;/span&gt; &lt;span class='hs-varid'&gt;ph&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;3. Here is where we actually specify a template to load dynamically:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;pages&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;PluginHandle&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;Response&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;pages&lt;/span&gt; &lt;span class='hs-varid'&gt;ph&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;    &lt;span class='hs-varid'&gt;msum&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;withServerPart&lt;/span&gt; &lt;span class='hs-chr'&gt;'&lt;/span&gt;&lt;span class='hs-varid'&gt;helloPage&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-varid'&gt;ph&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;\&lt;/span&gt;&lt;span class='hs-varid'&gt;helloPage&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;               &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;helloPage&lt;/span&gt; &lt;span class='hs-str'&gt;"hello"&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;         &lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Normally we would just have:&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;pages&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;PluginHandle&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;Response&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;pages&lt;/span&gt; &lt;span class='hs-varid'&gt;ph&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;    &lt;span class='hs-varid'&gt;msum&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt; &lt;span class='hs-varid'&gt;helloPage&lt;/span&gt; &lt;span class='hs-str'&gt;"world"&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;         &lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So the new part is the template haskell function &lt;code&gt;withServerPart&lt;/code&gt; which effectively takes three arguments:&lt;br /&gt;&lt;br /&gt; 1. the name of the symbol to dynamically load&lt;br /&gt; 2. the &lt;code&gt;PluginHandle&lt;/code&gt; which &lt;code&gt;initPlugins&lt;/code&gt; returned&lt;br /&gt; 3. a function which will use the loaded symbol&lt;br /&gt;&lt;br /&gt;so, &lt;code&gt;withServerPart&lt;/code&gt; effectively has the type:&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;withServerPart&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;MonadIO&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerMonad&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Name&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;PluginHandle&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;a&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt; &lt;span class='hs-varid'&gt;b&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt; &lt;span class='hs-varid'&gt;b&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;Even though we are dynamically reloaded the page at runtime, the compiler will still check that the types are correct when will compile the main application.&lt;br /&gt;&lt;br /&gt;If we change &lt;code&gt;helloPage "hello"&lt;/code&gt; to &lt;code&gt;helloPage 1&lt;/code&gt; and try to build Main.lhs we will get the error.&lt;br /&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;Main.lhs:50:28:&lt;br /&gt;    No instance for (Num String)&lt;br /&gt;      arising from the literal `1' at Main.lhs:50:28&lt;br /&gt;    Possible fix: add an instance declaration for (Num String)&lt;br /&gt;    In the first argument of `helloPage', namely `1'&lt;br /&gt;    In the expression: (helloPage 1)&lt;br /&gt;    In the second argument of `($)', namely&lt;br /&gt;        `\ helloPage -&gt; (helloPage 1)'&lt;br /&gt;Failed, modules loaded: HelloPage.&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;What's left to do?&lt;/h2&gt;&lt;br /&gt;&lt;br /&gt;There are two big features on the TODO list. If you think happstack-plugins is cool, I encourage you to work on them!&lt;br /&gt;&lt;br /&gt;1. The underlying plugins library is broken when it comes to hierarchical modules. Ideally I would put all the pages in &lt;code&gt;Pages.*&lt;/code&gt;. For example &lt;code&gt;Pages.HelloPage&lt;/code&gt;. But, that does not work. As a hack, you can modify &lt;code&gt;System.Plugins.Make.build&lt;/code&gt; and comment out &lt;code&gt;output&lt;/code&gt; in the &lt;code&gt;let flags = ...&lt;/code&gt; declaration. This fixes hierachical modules, but requires you to run your app with its working directory set to the root directory of your project. That is fine for happstack app development, but not an ideal solution for all users of the plugins library. If someone could fix hierarchical module support in plugins, that would be great for everyone.&lt;br /&gt;&lt;br /&gt;2. hinotify is only supported under Linux. However, it should not be that hard to make hinotify support optional (via a compile time flag). With out hinotify, we would just do a quick &lt;code&gt;stat()&lt;/code&gt; everytime the template is invoked and see if a recompilation is needed. When a compilation is needed, you will have to wait for that page to recompile and reload -- but it will still be much faster than rebuilding and restarting the whole server.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-3323041215675504349?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/3323041215675504349/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2010/10/recompile-your-haskell-based-templates.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/3323041215675504349'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/3323041215675504349'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2010/10/recompile-your-haskell-based-templates.html' title='Recompile your Haskell-based templates faster than you can hit F5.'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-1150819849659464374</id><published>2010-10-13T19:39:00.000-05:00</published><updated>2010-10-13T19:45:25.674-05:00</updated><title type='text'>Is the RqData monad still needed?</title><content type='html'>&lt;p&gt;cdsmitch &lt;a href="http://cdsmith.wordpress.com/2010/10/12/request-handling-in-snap-and-happstack-an-interesting-observation/"&gt;recently asked&lt;/a&gt; if &lt;code&gt;RqData&lt;/code&gt; is really needed in &lt;a href="http://www.happstack.com/"&gt;Happstack&lt;/a&gt;. The answer is, "no, but it is still useful sometimes."&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I can say "no" with certainty because in the darcs version of Happstack, it is already optional.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;The new and improved RqData&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Functions like &lt;code&gt;look&lt;/code&gt; now work in any monad which is an instance of &lt;code&gt;HasRqData&lt;/code&gt;:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;look&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Functor&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;Monad&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;HasRqData&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Since there is a &lt;code&gt;HasRqData&lt;/code&gt; instance for &lt;code&gt;ServerPart&lt;/code&gt;, we effectively have the function:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;look&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Here is an example of using &lt;code&gt;look&lt;/code&gt; with out having to jump through any hoops:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;module&lt;/span&gt; &lt;span class='hs-conid'&gt;Main&lt;/span&gt; &lt;span class='hs-keyword'&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;nullConf&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;simpleHTTP&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;ok&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPart&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPart&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-keyword'&gt;do&lt;/span&gt; &lt;span class='hs-varid'&gt;greeting&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt; &lt;span class='hs-str'&gt;"greeting"&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;        &lt;span class='hs-varid'&gt;noun&lt;/span&gt;     &lt;span class='hs-keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt; &lt;span class='hs-str'&gt;"noun"&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;        &lt;span class='hs-varid'&gt;ok&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;greeting&lt;/span&gt; &lt;span class='hs-varop'&gt;++&lt;/span&gt; &lt;span class='hs-str'&gt;", "&lt;/span&gt; &lt;span class='hs-varop'&gt;++&lt;/span&gt; &lt;span class='hs-varid'&gt;noun&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;IO&lt;/span&gt; &lt;span class='hs-conid'&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;simpleHTTP&lt;/span&gt; &lt;span class='hs-varid'&gt;nullConf&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;helloPart&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;Now if we visit &lt;a href="http://localhost:8000/?greeting=hello&amp;amp;noun=rqdata"&gt;http://localhost:8000/?greeting=hello&amp;amp;noun=rqdata&lt;/a&gt;, we will get the message &lt;i&gt;hello, rqdata&lt;/i&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Sweet!&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;But why keep RqData around?&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Using &lt;code&gt;look&lt;/code&gt; in the &lt;code&gt;ServerPart&lt;/code&gt; monad is simple. But when it fails, it just calls &lt;code&gt;mzero&lt;/code&gt;. That can be very frustrating if you are debugging your forms or debugging calls to your web service API. Instead of an error telling you what parameter was missing, you simply get a generic 404 error.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Using the &lt;code&gt;RqData&lt;/code&gt; monad/applicative functor gives you the option to provide detailed error messages when something goes wrong:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;module&lt;/span&gt; &lt;span class='hs-conid'&gt;Main&lt;/span&gt; &lt;span class='hs-keyword'&gt;where&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Control&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Applicative&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varop'&gt;&amp;lt;$&amp;gt;&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varop'&gt;&amp;lt;*&amp;gt;&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;badRequest&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;nullConf&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;ok&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;simpleHTTP&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;import&lt;/span&gt; &lt;span class='hs-conid'&gt;Happstack&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;Server&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;RqData&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;RqData&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;getDataFn&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloRq&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;RqData&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloRq&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-conid'&gt;(,)&lt;/span&gt; &lt;span class='hs-varop'&gt;&amp;lt;$&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt; &lt;span class='hs-str'&gt;"greeting"&lt;/span&gt; &lt;span class='hs-varop'&gt;&amp;lt;*&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt; &lt;span class='hs-str'&gt;"noun"&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPart&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;ServerPart&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;helloPart&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-keyword'&gt;do&lt;/span&gt; &lt;span class='hs-varid'&gt;r&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='hs-varid'&gt;getDataFn&lt;/span&gt; &lt;span class='hs-varid'&gt;helloRq&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;        &lt;span class='hs-keyword'&gt;case&lt;/span&gt; &lt;span class='hs-varid'&gt;r&lt;/span&gt; &lt;span class='hs-keyword'&gt;of&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;          &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Left&lt;/span&gt; &lt;span class='hs-varid'&gt;e&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;              &lt;span class='hs-varid'&gt;badRequest&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;unlines&lt;/span&gt; &lt;span class='hs-varid'&gt;e&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;          &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Right&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;greet&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;noun&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;              &lt;span class='hs-varid'&gt;ok&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;greet&lt;/span&gt; &lt;span class='hs-varop'&gt;++&lt;/span&gt; &lt;span class='hs-str'&gt;", "&lt;/span&gt; &lt;span class='hs-varop'&gt;++&lt;/span&gt; &lt;span class='hs-varid'&gt;noun&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;IO&lt;/span&gt; &lt;span class='hs-conid'&gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;main&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;simpleHTTP&lt;/span&gt; &lt;span class='hs-varid'&gt;nullConf&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;helloPart&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;If you visit &lt;a href="http://localhost:8000/?greeting=hello&amp;amp;noun=world"&gt;http://localhost:8000/?greeting=hello&amp;amp;noun=world&lt;/a&gt;, you will get the familiar greeting &lt;kbd&gt;hello, world&lt;/kbd&gt;.&lt;br /&gt;&lt;p&gt;But if you leave off the query parameters &lt;a href="http://localhost:8000/"&gt;http://localhost:8000/&lt;/a&gt;, you will get a list of errors:&lt;br /&gt;&lt;pre class="code"&gt;&lt;br /&gt;Parameter not found: greeting&lt;br /&gt;Parameter not found: noun&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This is &lt;i&gt;really nice&lt;/i&gt; when you are debugging your code.&lt;/p&gt;&lt;br /&gt;&lt;h3&gt;Now with more composability!&lt;/h3&gt;&lt;br /&gt;&lt;p&gt;Since &lt;code&gt;RqData&lt;/code&gt; and &lt;code&gt;ServerPart&lt;/code&gt; are instances of &lt;code&gt;Applicative&lt;/code&gt; and &lt;code&gt;Alternative&lt;/code&gt; you can now reuse many functions from those libraries. For example, if a query parameter is optional, you can simply write:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-keyword'&gt;do&lt;/span&gt; &lt;span class='hs-varid'&gt;greet&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;&amp;lt;-&lt;/span&gt; &lt;span class='hs-varid'&gt;optional&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-varid'&gt;look&lt;/span&gt; &lt;span class='hs-str'&gt;"greeting"&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;There is also a new combinator &lt;code&gt;checkRq&lt;/code&gt; which can be used to validate query parameters, or to convert a query parameter to another type:&lt;/p&gt;&lt;br /&gt;&lt;div class="code"&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;checkRq&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Monad&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;HasRqData&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt; &lt;span class='hs-varid'&gt;a&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;a&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Either&lt;/span&gt; &lt;span class='hs-conid'&gt;String&lt;/span&gt; &lt;span class='hs-varid'&gt;b&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;m&lt;/span&gt; &lt;span class='hs-varid'&gt;b&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;If you are curious be sure to check out the &lt;a href="http://www.happstack.com/docs/crashcourse/index.html"&gt;Happstack Crash Course&lt;/a&gt; where the new RqData module is &lt;a href="http://www.happstack.com/docs/crashcourse/RqData.html"&gt;documented in detail&lt;/a&gt; with many working examples.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I would love to hear feedback on the new and improved &lt;code&gt;RqData&lt;/code&gt; module, and any suggestions for improvement!&lt;/p&gt;&lt;br /&gt;&lt;p&gt;Also, be on the look out for a future blog post about the &lt;code&gt;RqData&lt;/code&gt; &lt;b&gt;&lt;code&gt;Arrow&lt;/code&gt;&lt;/b&gt;. :)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-1150819849659464374?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/1150819849659464374/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2010/10/is-rqdata-monad-still-needed.html#comment-form' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/1150819849659464374'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/1150819849659464374'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2010/10/is-rqdata-monad-still-needed.html' title='Is the RqData monad still needed?'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-4548701123532271599</id><published>2010-07-19T12:08:00.000-05:00</published><updated>2010-07-19T12:56:07.976-05:00</updated><title type='text'>Changes to request body and RqData in head</title><content type='html'>&lt;p&gt;I have just pushed some patches which affect the way the &lt;code&gt;Request&lt;/code&gt; body and &lt;code&gt;RqData&lt;/code&gt; are handled in happstack 0.6. This contains user visible changes which will affect you if you:&lt;/p&gt;&lt;br /&gt;&lt;ul&gt;&lt;br /&gt; &lt;li&gt;Use &lt;code&gt;RqData&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Directly use the &lt;code&gt;rqBody&lt;/code&gt; field in &lt;code&gt;Request&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Directly use the &lt;code&gt;rqInput&lt;/code&gt; field in &lt;code&gt;Request&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Directly work with the &lt;code&gt;Input&lt;/code&gt; type&lt;/li&gt;&lt;br /&gt; &lt;li&gt;Allow file uploads&lt;/li&gt;&lt;br /&gt;&lt;/ul&gt;&lt;br /&gt;&lt;p&gt;Some of the changes fix bugs (design flaws), and others are for new features and functionality. The non-compatible API changes are pretty small, so it should be easy to port your code. It basically comes down to:&lt;/p&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;getDataFn, withDataFn, etc&lt;/code&gt; take an extra argument of the type &lt;code&gt;BodyPolicy&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;&lt;code&gt;getDataFn, withDataFn, etc&lt;/code&gt; return &lt;code&gt;Either [String] a&lt;/code&gt; instead of &lt;code&gt;Maybe a&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;the &lt;code&gt;inputValue&lt;/code&gt; field of the &lt;code&gt;Input&lt;/code&gt; type is now &lt;code&gt;Either FilePath L.ByteString&lt;/code&gt; instead of &lt;code&gt;L.ByteString&lt;/code&gt;&lt;/li&gt;&lt;br /&gt; &lt;li&gt;you have to explicitly import the module &lt;code&gt;Happstack.Server.RqData&lt;/code&gt;&lt;/li&gt;&lt;br /&gt;&lt;/ol&gt;&lt;br /&gt;&lt;p&gt;In this post I will describe what motivated these changes. I am&lt;br /&gt;hoping to also get feedback and these changes before we release 0.6 since it will be less painful to make further changes now.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;the Request body and space usage&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;In the old code the &lt;code&gt;Request&lt;/code&gt; type stores the request body as a simple lazy &lt;code&gt;ByteString&lt;/code&gt;:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;newtype&lt;/span&gt; &lt;span class='hs-conid'&gt;RqBody&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;Body&lt;/span&gt; &lt;span class='hs-layout'&gt;{&lt;/span&gt; &lt;span class='hs-varid'&gt;unBody&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;L&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;ByteString&lt;/span&gt; &lt;span class='hs-layout'&gt;}&lt;/span&gt; &lt;span class='hs-keyword'&gt;deriving&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Read&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-conid'&gt;Show&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-conid'&gt;Typeable&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;data&lt;/span&gt; &lt;span class='hs-conid'&gt;Request&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;Request&lt;/span&gt; &lt;span class='hs-layout'&gt;{&lt;/span&gt; &lt;span class='hs-varop'&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                        &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;rqBody&lt;/span&gt;        &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;RqBody&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                        &lt;span class='hs-layout'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;This feels nice, because it is a simple, pure value. Unfortunately, it is really not a great idea in practice. The request body does not initially require any space, because it is an unevaluated lazy &lt;code&gt;ByteString&lt;/code&gt;. But the &lt;code&gt;ServerPart&lt;/code&gt; holds the &lt;code&gt;Request&lt;/code&gt; in its environment, and that means the garbage collection can not free the &lt;code&gt;RqBody&lt;/code&gt; as you evaluate it. If the request body contained gigabytes of data, that could be disastrous.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The solution in Happstack 0.6 is to use an &lt;code&gt;MVar&lt;/code&gt; to hold the request body:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;data&lt;/span&gt; &lt;span class='hs-conid'&gt;Request&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;Request&lt;/span&gt; &lt;span class='hs-layout'&gt;{&lt;/span&gt; &lt;span class='hs-varop'&gt;...&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                        &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;rqBody&lt;/span&gt;        &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;MVar&lt;/span&gt; &lt;span class='hs-conid'&gt;RqBody&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                        &lt;span class='hs-layout'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Instead of using &lt;code&gt;rqBody&lt;/code&gt; directly, it is better to use &lt;code&gt;takeRequestBody&lt;/code&gt;, so that your code will not break if we switch to &lt;code&gt;IORef&lt;/code&gt; or something else.&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;takeRequestBody&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Request&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;IO&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Maybe&lt;/span&gt; &lt;span class='hs-conid'&gt;RqBody&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;takeRequestBody&lt;/span&gt; &lt;span class='hs-varid'&gt;rq&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;tryTakeMVar&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;rqBody&lt;/span&gt; &lt;span class='hs-varid'&gt;rq&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Now, when you process the &lt;code&gt;RqBody&lt;/code&gt; the &lt;code&gt;Request&lt;/code&gt; will not be holding onto it, so the garbage collection can free it (assuming &lt;b&gt;your&lt;/b&gt; code to not hold onto it and introduce a new space leak).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;This does have a drawback however. A &lt;code&gt;ServerPart&lt;/code&gt; can call &lt;code&gt;mzero&lt;/code&gt; at anytime, and processing will move onto the next &lt;code&gt;ServerPart&lt;/code&gt;. However, if you have already taken the &lt;code&gt;RqBody&lt;/code&gt; then the next &lt;code&gt;ServerPart&lt;/code&gt; may be missing critical data it needs. But, if we left the &lt;code&gt;RqBody&lt;/code&gt; intact, that would result in the space leak. I think that in practice, if a &lt;code&gt;ServerPart&lt;/code&gt; made enough progress that it started consuming the &lt;code&gt;RqBody&lt;/code&gt; and then failed, it is unlikely that another &lt;code&gt;ServerPart&lt;/code&gt; would succeed and need the &lt;code&gt;RqBody&lt;/code&gt;. If another &lt;code&gt;ServerPart&lt;/code&gt; succeeds, it is probably just a &lt;code&gt;404 Not Found&lt;/code&gt; handler or something similar, which does not need the request body. So it seems like it is better to have the default behavior be the more space friendly solution.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;We will also provide &lt;code&gt;peekRequestBody&lt;/code&gt; and/or &lt;code&gt;putRequestBody&lt;/code&gt; functions so that you can opt to leave the request body intact. It is up to you to be sensible about using them.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;code&gt;BodyInput&lt;/code&gt; and space usage&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;In RqData, the cookies, QUERY_STRING, and request body (when appropriate) are parsed into a &lt;code&gt;[(String, Input)]&lt;/code&gt;, where &lt;code&gt;String&lt;/code&gt; is the name of the key, and &lt;code&gt;Input&lt;/code&gt; is the value.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In Happstack 0.6, &lt;code&gt;Input&lt;/code&gt; will be the type:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;data&lt;/span&gt; &lt;span class='hs-conid'&gt;Input&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;Input&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-layout'&gt;{&lt;/span&gt; &lt;span class='hs-varid'&gt;inputValue&lt;/span&gt;       &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Either&lt;/span&gt; &lt;span class='hs-conid'&gt;FilePath&lt;/span&gt; &lt;span class='hs-conid'&gt;L&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-conid'&gt;ByteString&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;inputFilename&lt;/span&gt;    &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Maybe&lt;/span&gt; &lt;span class='hs-conid'&gt;FilePath&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;inputContentType&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;ContentType&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;     &lt;span class='hs-layout'&gt;}&lt;/span&gt; &lt;span class='hs-keyword'&gt;deriving&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Show&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-conid'&gt;Read&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-conid'&gt;Typeable&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;In Happstack 0.5 the &lt;code&gt;inputValue&lt;/code&gt; is simply a &lt;code&gt;L.ByteString&lt;/code&gt;. Once again, this seems fine at first. After all, the &lt;code&gt;inputValues&lt;/code&gt; are lazy &lt;code&gt;ByteString&lt;/code&gt;, so we can process them lazily, right? Well, not quite. In the unprocessed request body, the key/value pairs are laid out like this:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;key1&lt;br /&gt;value1&lt;br /&gt;key2&lt;br /&gt;value2&lt;br /&gt;key3&lt;br /&gt;value3&lt;br /&gt;key4&lt;br /&gt;value4&lt;br /&gt;...&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;If we were to consume the key/value pairs in a sequential manner, then we would be ok. But, generally we want to use functions which can lookup a specific key. Imagine we want to look up &lt;code&gt;key4&lt;/code&gt;. In order to do that we have to first read in all the preceding key/value pairs. If we knew we only cared about &lt;code&gt;key4&lt;/code&gt; then we could just toss the rest. But with the monadic &lt;code&gt;RqData&lt;/code&gt; code we don't know that. (A future post will talk about an arrow based alternative where we do know that). So, we have to store all the key/value pairs in case we want to lookup &lt;code&gt;key1&lt;/code&gt; after &lt;code&gt;key4&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In Happstack 0.5, we store all those values in RAM. But, some of those values might be (huge) files. That clearly isn't going to work. So we once again trade off a bit a simplicity/elegance for the practical matter of not having unlimited amounts of RAM. Instead we store some values in RAM and some values on the disk. How do we decide what goes where? That brings us to &lt;code&gt;BodyPolicy&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;&lt;code&gt;BodyPolicy&lt;/code&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;When parsing the request body, we need some way to decide what values should be stored in RAM and what values should be saved to disk. Additionally, we want to impose limits on how much data can be stored in either location. If a user decides to post the contents of &lt;kbd&gt;/dev/random&lt;/kbd&gt; you are likely to want to cut them off at some point. However, the specific values for the quotas are application specific. In fact, they may be specific to the particular form that is being processed. For example, an admin user might have higher quotas than a regular user.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;The answers to these questions are provided by the &lt;code&gt;BodyPolicy&lt;/code&gt;, which looks like:&lt;/p&gt;&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-keyword'&gt;data&lt;/span&gt; &lt;span class='hs-conid'&gt;BodyPolicy&lt;/span&gt; &lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;    &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;BodyPolicy&lt;/span&gt; &lt;span class='hs-layout'&gt;{&lt;/span&gt; &lt;span class='hs-varid'&gt;inputWorker&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;InputWorker&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                 &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;maxDisk&lt;/span&gt;     &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-comment'&gt;-- ^ maximum bytes to save to disk (files)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                 &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;maxRAM&lt;/span&gt;      &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-comment'&gt;-- ^ maximum bytes to hold in RAM &lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                 &lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;maxHeader&lt;/span&gt;   &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-comment'&gt;-- ^ maximum header size (this only affects headers in the multipart/form-data)&lt;/span&gt;&lt;br /&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt;                 &lt;span class='hs-layout'&gt;}&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The &lt;code&gt;inputWorker&lt;/code&gt; is the function that actually decides where values should be saved, and implements the quotas. Its &lt;code&gt;Int64&lt;/code&gt; arguments are the quotas for the disk, ram, and other headers which don't really get saved, but which can temporarily take up space. The next three fields are the values to pass to the &lt;code&gt;inputWorker&lt;/code&gt;.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;In most cases, you do not need to write you own &lt;code&gt;inputWorker&lt;/code&gt;. It is sufficient to use the &lt;code&gt;defaultBodyPolicy&lt;/code&gt;:&lt;br /&gt;&lt;pre&gt;&lt;span class='hs-varop'&gt;&amp;gt;&lt;/span&gt; &lt;span class='hs-definition'&gt;defaultBodyPolicy&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;FilePath&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Int64&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;BodyPolicy&lt;/span&gt;&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;The first argument is the directory to store temporary files in, and the next three arguments are the quota values. I am not going to cover &lt;code&gt;defaultBodyPolicy&lt;/code&gt; in detail in this post. But it is well documented in the &lt;a href="http://happstack.com/docs/crashcourse/index.html"&gt;Happstack Crash Course&lt;/a&gt;.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Improvements to &lt;code&gt;RqData&lt;/code&gt;&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;The new &lt;code&gt;RqData&lt;/code&gt; module also includes a number of new features.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;There is now an &lt;code&gt;Applicative&lt;/code&gt; functor instance for &lt;code&gt;RqData&lt;/code&gt;. The applicative functor instance accumulates errors. This means if you try look up multiple invalid keys, the error message will report all the missing values, not just the first one. This is nice when you are debugging your code, and is also nice if you provide a web service (REST API, etc) and want to provide your API users with detailed error messages instead of "Invalid Request".&lt;/p&gt;&lt;br /&gt;&lt;p&gt;We now provide two filters (&lt;code&gt;body&lt;/code&gt; and &lt;code&gt;queryString&lt;/code&gt;) which limit the scope of the look* functions to either the request body or the QUERY_STRING.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A new function &lt;code&gt;lookFile&lt;/code&gt; is provided to assist with handling file uploads.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;A new function &lt;code&gt;checkRq&lt;/code&gt; is provided to help you convert&lt;br /&gt;request parameters to Haskell types, or to check that a value meets some conditions.&lt;/p&gt;&lt;br /&gt;&lt;h2&gt;Summary&lt;/h2&gt;&lt;br /&gt;&lt;p&gt;This post gives some of the background on the changes to how we handle the request body and form data. To actually see what the changes look like in practice, you should check out the &lt;a href="http://happstack.com/docs/crashcourse/RqData.html"&gt;RqData&lt;/a&gt; section in the Happstack Crash Course. It gives detailed examples of all the features and changes I talked about in this post. I have also updated the haddock documentation in darcs.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;I would love to hear your opinions. Do you love the changes? Hate the changes? Have better ideas about how to solve the problems? In terms of handling the raw request body, I believe both Yesod and Snap use the same basic approach -- the first handler to try to use the request body gets the whole thing, and everyone else gets nothing. (And they provide ways to put the request body back if you want to..).&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-4548701123532271599?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/4548701123532271599/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2010/07/changes-to-request-body-and-rqdata-in.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/4548701123532271599'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/4548701123532271599'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2010/07/changes-to-request-body-and-rqdata-in.html' title='Changes to request body and RqData in head'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3300386911011555799.post-8046034100206544266</id><published>2010-07-11T16:12:00.000-05:00</published><updated>2010-07-11T16:57:15.391-05:00</updated><title type='text'>sendfile 0.7.1</title><content type='html'>I have just uploaded &lt;a href='http://hackage.haskell.org/package/sendfile'&gt;sendfile 0.7.1&lt;/a&gt; to hackage.&lt;br /&gt;&lt;br /&gt;The sendfile library exposes zero-copy sendfile functionality in a portable way. If a platform does not support sendfile, a fallback implementation in Haskell is provided. It currently has zero-copy support for Linux, Darwin, FreeBSD, and Windows.&lt;br /&gt;&lt;br /&gt;The sendfile functionality typically reduces CPU-load and (possibly) increases IO throughput.&lt;br /&gt;&lt;br /&gt;The new release of sendfile adds the ability to hook into the send loop. This is useful if you want to tickle timeouts or update a progress bar while the file is being sent. &lt;br /&gt;&lt;br /&gt;This turned out to be rather tricky because each platform implements sendfile a little differently. But, the point of the sendfile library is to provide a unified interface so that other developers do not have to know any of the platform specific details.&lt;br /&gt;&lt;br /&gt;The solution in 0.7.1 is to use a simple, specialized iteratee. Each pass of the sendfile loop can end in one of three states:&lt;br /&gt;&lt;br /&gt; (1) the requested number of bytes for that iteration was sent&lt;br /&gt; successfully, there are more bytes left to send.&lt;br /&gt;&lt;br /&gt; (2) some (possibly 0) bytes were sent, but the file descriptor&lt;br /&gt; would now block if more bytes were written. There are more bytes&lt;br /&gt; left to send.&lt;br /&gt;&lt;br /&gt; (2) All the bytes were sent, and there is nothing left to send.&lt;br /&gt;&lt;br /&gt;We handle these three cases by using a type with three&lt;br /&gt;constructors:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt; data Iter&lt;br /&gt;     = Sent       Int64    (IO Iter)&lt;br /&gt;     | WouldBlock Int64 Fd (IO Iter)&lt;br /&gt;     | Done       Int64             &lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;All three constructors provide an &lt;code&gt;Int64&lt;/code&gt; which represents the&lt;br /&gt;number of bytes sent for that particular iteration. (Not the total&lt;br /&gt;byte count).&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;Sent&lt;/code&gt; and &lt;code&gt;WouldBlock&lt;/code&gt; constructors provide &lt;code&gt;IO Iter&lt;/code&gt; as their&lt;br /&gt;final argument. Running this IO action will send the next block of&lt;br /&gt;data.&lt;br /&gt;&lt;br /&gt;The &lt;code&gt;WouldBlock&lt;/code&gt; constructor also provides the &lt;code&gt;Fd&lt;/code&gt; for the output&lt;br /&gt;socket. You should not send anymore data until the &lt;code&gt;Fd&lt;/code&gt; would not&lt;br /&gt;block. The easiest way to do that is to use &lt;code&gt;threadWaitWrite&lt;/code&gt; to&lt;br /&gt;suspend the thread until the &lt;code&gt;Fd&lt;/code&gt; is available.&lt;br /&gt;&lt;br /&gt;A very simple function to drive the Iter might look like:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;runIter :: IO Iter -&gt; IO ()&lt;br /&gt;runIter iter =&lt;br /&gt;   do r &lt;- iter&lt;br /&gt;      case r of&lt;br /&gt;        (Done _n)      -&gt; return ()&lt;br /&gt;        (Sent _n cont) -&gt; runIter cont&lt;br /&gt;        (WouldBlock _n fd cont) -&gt; &lt;br /&gt;            do threadWaitWrite fd&lt;br /&gt;               runIter cont&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;You would use it as the first argument to a *IterWith function, e.g.&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt; sendFileIterWith runIter outputSocket "/path/to/file" 2^16 &lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;If we want to do something fancier, such as update timeouts or a progress bar, we can do it in a custom runIter function. If we are using a non-standard I/O manager, we might be able to suspend the thread via a call other than &lt;code&gt;threadWaitWrite&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;h2&gt;What Next?&lt;/h2&gt;&lt;br /&gt;The new version of sendfile will be used to improve the timeout handling in the Haskell web framework, &lt;a href="http://www.happstack.com/"&gt;Happstack&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;It would be nice if the sendfile library could export a low-level function like:&lt;br /&gt;&lt;code&gt;&lt;pre&gt;&lt;br /&gt;sendfile :: Fd -&gt; Fd -&gt; Int64 -&gt; Int64 -&gt; IO (Bool, Int64)&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;br /&gt;It would take the output socket, and input file descriptor, an offset, and length, and  return the number of bytes written, and whether the output socket blocked.&lt;br /&gt;&lt;br /&gt;Unfortunately, it is not possible to provide a portable implementation of this &lt;code&gt;sendfile&lt;/code&gt; function. That would require functions which can operate directly on the &lt;code&gt;Fds&lt;/code&gt;. But those functions live in the &lt;code&gt;unix&lt;/code&gt; package, which is not portable. &lt;br /&gt;&lt;br /&gt;Another non-solution is to have a module like, &lt;code&gt;Network.Socket.SendFile.LowLevel&lt;/code&gt; which is only exported on the platforms which provide a low-level sendfile implementation. However, it is my understanding that this is not really allowed by the cabal policy because there would be no way to specify that you require a version of the sendfile library that exports &lt;code&gt;.LowLevel&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;So, I believe a more correct solution is to create a *new* package, &lt;code&gt;sendfile-lowlevel&lt;/code&gt;, which exports &lt;code&gt;Network.Socket.SendFile.LowLevel&lt;/code&gt;. This assumes that there is some way to mark that a package is only available on certain platforms. However, I am not sure if that can be done.&lt;br /&gt;&lt;br /&gt;Hopefully the new API provides enough flexibility that there is no need for an even lower-level API to be exposed. If you think you need something lower-level, let me know, and let's see if we can work something out.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3300386911011555799-8046034100206544266?l=happstack.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://happstack.blogspot.com/feeds/8046034100206544266/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://happstack.blogspot.com/2010/07/sendfile-071.html#comment-form' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8046034100206544266'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3300386911011555799/posts/default/8046034100206544266'/><link rel='alternate' type='text/html' href='http://happstack.blogspot.com/2010/07/sendfile-071.html' title='sendfile 0.7.1'/><author><name>Jeremy Shaw</name><uri>http://www.blogger.com/profile/18373967098081701148</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='21' height='32' src='http://www.alchymiastudio.com/refs/DSC_5723-small.jpg'/></author><thr:total>1</thr:total></entry></feed>
