<?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-3601356092114855287</id><updated>2011-10-10T17:32:12.281-07:00</updated><title type='text'>Coding for the Big Picture</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>14</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-3466629974075162185</id><published>2011-01-11T23:44:00.001-08:00</published><updated>2011-01-11T23:44:04.547-08:00</updated><title type='text'>A Categorical Treatment of Romance</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;p.p1 {margin: 0.0px 0.0px 13.0px 0.0px; font: 9.0px Arial} p.p2 {margin: 0.0px 0.0px 13.0px 0.0px; font: 13.0px Arial} span.s1 {color: #ffffff} span.s2 {text-decoration: underline}  &lt;p class="p1"&gt;Or, why Information Theory is more touchy-feely than classical E&amp;amp;M.&lt;/p&gt;  &lt;p class="p2"&gt;You folks are familiar with the concept of a duality, yes? Then what is the usual loser scenario for guys? You dote on some girl with all this attention but then she runs away with some motorcycle dude, right? And to add insult to injury, she complains about him to you afterwards.&lt;/p&gt;  &lt;p class="p2"&gt;What would be duality of this situation? Just reverse the arrows, yes? I don't want you to get to an answer without thinking about it, so take some time to muse a little, then highlight the text after this sentence.&amp;nbsp;&lt;span class="s1"&gt;You're a girl. No one calls you, not even that motorcycle dude you gave it up for. "I hope he dies in an accident. Asshole." ;-)&lt;/span&gt;&lt;/p&gt;  &lt;p class="p2"&gt;Now there is a catch here, because this seems to have violated conservation of attention. It's like integrating the magnetic flux over a closed continuous surface, yknow? Should sum to zero.* Alas, the physically correct description of the world is totally useless to us. We have a glimmer of hope, however. See, if you step back and think about it,... If you give unconditional attention, is it still attention? ;-) Remember, it takes only &lt;span class="s2"&gt;one&lt;/span&gt; bit to encode unconditional attention.** One. Bit. :-) Admittedly, this reconciliation requires Information Theory, but what &lt;em&gt;matters&lt;/em&gt; is that the math works!! :-D ***&lt;/p&gt;  &lt;p class="p2"&gt;I wonder how many analogies I can butcher with dualities, and which supplementary theories I will need to grease the &lt;span style="text-decoration: line-through;"&gt;axe&lt;/span&gt;&amp;nbsp;uh I mean logic...&lt;/p&gt;  &lt;p class="p1"&gt;[*] Maxwell's equation for magnetic flux works particularly well here when you imagine how the positive and negative nature of the interaction would play out. ;-) And the fact that it sums to zero. Face it, kid. There is no magnetic monopole.&lt;/p&gt;  &lt;p class="p1"&gt;[**] Kindly consider that girls may find one-bit guys to be cute, but ultimately a little annoying. And that giving it up to those cool boys riding motorcycles can also be encoded in one bit. Happy romancing, and try to not say anything stupid! :-)&lt;/p&gt;  &lt;p class="p1"&gt;[***] The solution to maths is&amp;hellip; MOAR MATHS!&lt;/p&gt;  &lt;/p&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/a-categorical-treatment-of-romance"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-3466629974075162185?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/3466629974075162185/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=3466629974075162185' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/3466629974075162185'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/3466629974075162185'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2011/01/categorical-treatment-of-romance_11.html' title='A Categorical Treatment of Romance'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-8977956182243386708</id><published>2010-11-08T15:51:00.001-08:00</published><updated>2010-11-08T15:51:03.093-08:00</updated><title type='text'>An import trick too useful to pass up</title><content type='html'>&lt;div class='posterous_autopost'&gt;So here is a trick I learned from reading the Snap code over the last week.&lt;p /&gt;&lt;div&gt;Namespace collisions suck. Data.Map, Data.Set and Data.List all have fairly similar functions that we all know and love to use, and they differ subtly, so people often import them qualified, i.e.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;import qualified Data.Map as M&lt;/div&gt;&lt;div&gt;import qualified Data.Set as S&lt;/div&gt;&lt;div&gt;import qualified Data.List as L&lt;/div&gt;&lt;p /&gt;&lt;div&gt;Now the annoying thing about this is that then you have to prepend the type signatures too, e.g.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;foobar :: S.Set a -&amp;gt; a -&amp;gt; S.Set a&lt;/div&gt;&lt;p /&gt;&lt;div&gt;This is pissy, so what some genius who worked on Snap did was:&lt;/div&gt;&lt;p /&gt;&lt;div&gt;&lt;div&gt; import Data.Map (Map)&lt;/div&gt;&lt;div&gt;import qualified Data.Map as M&lt;/div&gt;&lt;/div&gt;&lt;div&gt;import Data.Either (Left,Right)&lt;/div&gt;&lt;p /&gt;&lt;div&gt;Now this sounds simple and all, but it actually works Much Better in practice than in theory, partly because type constructors like Left and Right rarely overlap from module to module.&lt;/div&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/an-import-trick-too-useful-to-pass-up"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-8977956182243386708?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/8977956182243386708/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=8977956182243386708' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/8977956182243386708'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/8977956182243386708'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/11/import-trick-too-useful-to-pass-up.html' title='An import trick too useful to pass up'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-1586628921291201501</id><published>2010-11-08T15:40:00.001-08:00</published><updated>2010-11-08T15:40:05.453-08:00</updated><title type='text'>How *do* you tell good code from bad anyway?</title><content type='html'>&lt;div class='posterous_autopost'&gt;So here&amp;#39;s one straightforward metric for code cleanliness. Is there code that could&amp;#39;ve been purely functional that can&amp;#39;t be easily be extracted from the monadic wrappers you placed it in? I guess a similar thing for OCaml would&amp;#39;ve applied to the OO and functional code.&lt;p /&gt;&lt;div&gt;This is probably not as easy as it seems though, because there&amp;#39;s plenty of stuff that would&amp;#39;ve looked like it could&amp;#39;ve been pure but is actually much better off effectful. Sometimes there&amp;#39;s no substitute of experience.&lt;/div&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/how-do-you-tell-good-code-from-bad-anyway"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-1586628921291201501?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/1586628921291201501/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=1586628921291201501' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1586628921291201501'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1586628921291201501'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/11/how-do-you-tell-good-code-from-bad.html' title='How *do* you tell good code from bad anyway?'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-8140275717751653352</id><published>2010-09-10T22:13:00.001-07:00</published><updated>2010-09-10T22:13:35.015-07:00</updated><title type='text'>Untitled</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;A few months ago, there was a useful tutorial on using CouchDB with Haskell. You can find the original here.&lt;/p&gt;  &lt;p&gt;One weakness of these DB layers is that you have to verify your data, and the APIs to the input data are usually not typesafe. As it turns out, it's incredibly easy to use type-level programming to make your DB calls typesafe.&lt;/p&gt;  &lt;p&gt;Lets take an idealized version of a typical DB get call:&lt;/p&gt;  &lt;p&gt;&lt;code&gt;getDBUnsafe :: (JSON a) =&amp;gt; DB -&amp;gt; String -&amp;gt; IO a&lt;br /&gt; getDBUnsafe = undefined&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;There's two weak spots here. The first is the part where we pass in the DB key, and the second is when we use the value. The latter is more insidious than the former, because whatever it is you're using to parse your JSON, it's probably a pure function, so if you're coding in the usual expedient way, you'll have no idea why the parse is failing, when the real cause is that you're fetching from the wrong DB.&lt;/p&gt;  &lt;p&gt;So here's the framework for a solution that uses FunctionalDependencies and&amp;nbsp;&lt;span style="font-family: monospace;"&gt;MultiParamTypeClasses&lt;/span&gt;&amp;nbsp;to impose a constraint on the type of the DB key and stored value, based on the type of the DB.&lt;/p&gt;  &lt;p&gt;&lt;code&gt; class (JSON v) =&amp;gt; DBTy a k v | a -&amp;gt; k, a -&amp;gt; v where&lt;br /&gt; getDBName :: a -&amp;gt; String&lt;br /&gt; getKey :: a -&amp;gt; k -&amp;gt; String&lt;br /&gt; &lt;br /&gt; getDB :: (DBTy a k v) =&amp;gt; a -&amp;gt; k -&amp;gt; IO v&lt;br /&gt; getDB db k =&lt;br /&gt; getDBUnsafe (getDBName db) (getKey db k)&lt;br /&gt; &lt;br /&gt; &lt;/code&gt;&lt;/p&gt;  &lt;p&gt;So how we use this? Well you just define a dummy type for a DB like such:&lt;/p&gt;  &lt;p&gt;&lt;code&gt; type UserId = Int&lt;br /&gt; &lt;br /&gt; data Avatar&lt;br /&gt; = Avatar ByteString&lt;br /&gt; deriving (Eq, Show, Ord, Typeable, Data)&lt;br /&gt; &lt;br /&gt; instance JSON Avatar where&lt;br /&gt; showJSON = toJSON&lt;br /&gt; readJSON = fromJSON&lt;br /&gt; &lt;br /&gt; data AvatarsDB&lt;br /&gt; = AvatarsDB String&lt;br /&gt; &lt;br /&gt; instance DBTy AvatarsDB Int Avatar where&lt;br /&gt; getDBName (AvatarsDB name) = name&lt;br /&gt; getKey _ = show&lt;/code&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;After that, you just replace your unsafe DB calls that look like this:&lt;/p&gt;  &lt;p&gt;&lt;code&gt; v &amp;lt;- getDBUnsafe "avatars" userId &lt;/code&gt;&lt;/p&gt;  &lt;p&gt;with this:&lt;/p&gt;  &lt;p&gt;&lt;code&gt; v &amp;lt;- getDB AvatarsBB userId &lt;/code&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;Oh and here's the stuff you need to paste at the top of all this to get it to compile.&lt;/p&gt;  &lt;p&gt;&lt;span style="font-family: monospace;"&gt;{-# LANGUAGE FunctionalDependencies, MultiParamTypeClasses, DeriveDataTypeable #-}&lt;br /&gt;module FundepsExample where&lt;p /&gt;import Data.ByteString.Lazy&lt;p /&gt;import Text.JSON&lt;br /&gt;import Text.JSON.Generic&lt;p /&gt;type DB = String&lt;/span&gt;&lt;/p&gt;  &lt;p&gt;&amp;nbsp;&lt;/p&gt;  &lt;p&gt;I know it's a pretty silly example and use case, but I was surprised that there were folks in my local Haskell meetup who hadn't seen it, so I thought I should share it. It's saved me no end of errors ever since I put it to use.&lt;/p&gt;  &lt;p&gt;Now in practice, I've found it more useful to create a KeyStringTy class instead of using that getKey bit. As it so happens, the sort of stuff I typically use to index my &lt;span style="text-decoration: line-through;"&gt;bit bucket&lt;/span&gt; database are also the sort of stuff that I use in RPC calls from the web. It's probably less correct, but it sure was dandier to code. Watch it bite me in the ass someday.&lt;/p&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/27850237"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-8140275717751653352?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/8140275717751653352/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=8140275717751653352' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/8140275717751653352'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/8140275717751653352'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/09/untitled.html' title='Untitled'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-1083380643384649959</id><published>2010-08-17T15:52:00.001-07:00</published><updated>2010-08-17T15:52:45.430-07:00</updated><title type='text'>I just had to post this ...</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;img src="http://posterous.com/getfile/files.posterous.com/lambdasquirrel/JMhv0JFWux3IL8vj7NngujGTaYsKS2FiJJisyP2A1eaAyZYa0GCyJYq1sq8J/caffeine.jpg" width="492" height="518"/&gt;  &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/i-just-had-to-post-this"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-1083380643384649959?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/1083380643384649959/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=1083380643384649959' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1083380643384649959'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1083380643384649959'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/08/i-just-had-to-post-this.html' title='I just had to post this ...'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-5490859918514446206</id><published>2010-06-21T13:11:00.001-07:00</published><updated>2010-06-21T13:11:26.151-07:00</updated><title type='text'>Mike Rowe Celebrates Dirty Jobs</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;div&gt;&lt;object height="326" width="446"&gt;&lt;param name="movie" value="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" /&gt;&lt;/param&gt;&lt;param name="allowFullScreen" value="true" /&gt;&lt;param name="wmode" value="transparent" /&gt;&lt;/param&gt;&lt;param name="bgColor" value="#ffffff" /&gt;&lt;/param&gt; &lt;param name="flashvars" value="vu=http://video.ted.com/talks/dynamic/MikeRowe_2008P-high.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/MikeRowe-2008P.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=477" /&gt;&lt;embed src="http://video.ted.com/assets/player/swf/EmbedPlayer.swf" allowFullScreen="true" type="application/x-shockwave-flash" wmode="transparent" height="326" pluginspace="http://www.macromedia.com/go/getflashplayer" bgColor="#ffffff" flashvars="vu=http://video.ted.com/talks/dynamic/MikeRowe_2008P-high.flv&amp;su=http://images.ted.com/images/ted/tedindex/embed-posters/MikeRowe-2008P.embed_thumbnail.jpg&amp;vw=432&amp;vh=240&amp;ap=0&amp;ti=477" width="446"&gt;&lt;/embed&gt;&lt;/object&gt;&lt;/div&gt;&lt;p /&gt;&lt;div&gt;I couldn&amp;#39;t agree with this guy more. The cultural dynamic has led to more than a few awkward conversations about how programming doesn&amp;#39;t interest you anymore. Then there&amp;#39;s some equally silly remark on how one could remedy the problem with -insert-deux-ex-machina- here. Or an even more awkward defensive remark about how X is still interesting, the other guy just hasn&amp;#39;t seen aspect A of X.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;It&amp;#39;s nearly impossible to talk about things like work ethic and the psychology of motivation with such a dynamic. People tend to fall into one of three camps: that they do work simply because it has to be done (i.e. it&amp;#39;s a responsibility, so shut up), that they do their work because of the money it earns them, or that they&amp;#39;ll only do those things that pulls their heartstrings. You don&amp;#39;t get very far when a conversation usually devolves into some sort of argument over philosophies or personality traits.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;Perhaps that&amp;#39;s why Self-Determination Theory works so well: it bypasses the problem entirely. In the context of a conversation however, I wonder whether the smart thing to do is to keep quiet because there does not seem to be a right answer. I personally came from the third camp, but doing a startup quickly teaches you that passion alone can&amp;#39;t carry you the whole way.&lt;/div&gt; &lt;p /&gt;&lt;div&gt;&lt;div&gt;I wonder how many other creative industries suffer from this problem, and in what way, because I&amp;#39;m sure that the problem manifests itself differently depending on the field.&lt;/div&gt;&lt;p /&gt; &lt;/div&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/mike-rowe-celebrates-dirty-jobs-2"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-5490859918514446206?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/5490859918514446206/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=5490859918514446206' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5490859918514446206'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5490859918514446206'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/06/mike-rowe-celebrates-dirty-jobs.html' title='Mike Rowe Celebrates Dirty Jobs'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-5325074129977977109</id><published>2010-05-19T00:27:00.001-07:00</published><updated>2010-05-19T00:27:09.815-07:00</updated><title type='text'>Haskell &amp; STM, Why no Applicative?</title><content type='html'>&lt;div class='posterous_autopost'&gt;&lt;p&gt;There was a fellow on #haskell the other day who was apprehensive about learning STM. Should he learn it after learning category theory? We assured him that Haskell's STM was fairly simple, whereas category theory is a dense liberal art that you study to enrich your mind. Someone pointed him to the wiki and he went on his way.&lt;/p&gt;  &lt;p&gt;Afterwards, I perused the wiki (again). What struck me was that there was no example there that show you how to convert a plain old bunch of IO routines into STM routines. When I went to make one myself, I realized how brain-dead easy it is, but that there's something missing...&lt;/p&gt;  &lt;p&gt;Anyway, here's a chalked up example where someone has to perform multiple time-consuming tasks (preferably in parallel), with the interesting routine in &lt;strong&gt;bold&lt;/strong&gt;:&lt;/p&gt;  &lt;div&gt; &lt;br /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Control.Applicative&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Control.Monad&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Control.Concurrent&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Control.Concurrent.STM&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Control.Concurrent.STM.TMVar&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;import Data.DateTime&lt;/span&gt;&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;  &lt;/span&gt;&lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;main :: IO ()&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;main =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do putStrLn "Without STM"&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       t1s &amp;lt;- getCurrentTime&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       stuff &amp;lt;- withoutSTM&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       t1e &amp;lt;- getCurrentTime&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       putStrLn $ show stuff&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       putStrLn $ "That took " ++ show (diffSeconds t1e t1s) ++ " seconds"&lt;/span&gt;&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;-- this is the routine that actually does stuff&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;withoutSTM :: IO GroceryStore&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;withoutSTM =&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do a &amp;lt;- &lt;/span&gt;&lt;span style="font-family: courier new, monospace;"&gt;getTomatoesCountFromDB&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       b &amp;lt;- &lt;/span&gt;&lt;span style="font-family: courier new, monospace;"&gt;haveFreshBerries&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       c &amp;lt;- &lt;/span&gt;&lt;span style="font-family: courier new, monospace;"&gt;getNameOfCurrentStore&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return $&lt;/span&gt;&lt;span style="font-family: courier new, monospace;"&gt; GroceryStore a b c&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;getTomatoesCountFromDB :: IO Int&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;getTomatoesCountFromDB =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do milliSleep 1000  -- simulate slow DB read&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return 5&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;haveFreshBerries :: IO Bool&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;haveFreshBerries =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do milliSleep 1000&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return True&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;getNameOfCurrentStore :: IO String&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;getNameOfCurrentStore =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do milliSleep 1000&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return "Tom's Produce"&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;data GroceryStore&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    = GroceryStore&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;      { numTomatoes :: Int&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;      , freshBerriesInStock :: Bool&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;      , nameOfStore :: String&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;      }&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    deriving (Eq, Show, Ord)&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt; &lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;  &lt;/span&gt;&lt;div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;-- helpers&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;milliSleep = threadDelay . (*) 1000&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;So there you have the plain old imperative code.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;And here is the same code modified to use STM.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;-- getTomatoesCountFromDB, haveFreshBerries, getNameOfCurrentStore are unchanged from before&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;-- this is the modified routine&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;withSTM :: IO GroceryStore&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;withSTM =&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do a &amp;lt;- stmFork getTomatoesCountFromDB&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       b &amp;lt;- stmFork haveFreshBerries&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       c &amp;lt;- stmFork getNameOfCurrentStore&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;       GroceryStore &amp;lt;$&amp;gt; (stmWait a)&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;                    &amp;lt;*&amp;gt; (stmWait b)&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;div&gt;&lt;strong&gt;&lt;span style="font-family: courier new, monospace;"&gt;                    &amp;lt;*&amp;gt; (stmWait c)&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;main :: IO ()&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;main =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do putStrLn "With STM"&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       t2s &amp;lt;- getCurrentTime&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       stuffWithSTM &amp;lt;- withSTM&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       t2e &amp;lt;- getCurrentTime&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       putStrLn $ show stuffWithSTM&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       putStrLn $ "That took " ++ show (diffSeconds t2e t2s) ++ " seconds"&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return ()&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;p /&gt;  &lt;p /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;-- more helpers&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;stmWait = atomically&lt;/span&gt;&lt;/div&gt;  &lt;p /&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;stmFork :: IO a -&amp;gt; IO (STM a)&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;stmFork m =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do tmv &amp;lt;- newEmptyTMVarIO&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       let m' = m &amp;gt;&amp;gt;= (atomically . putTMVar tmv)&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       forkIO m'&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return $ readTMVar tmv&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;Now the folks who've been playing with this for a while won't find this particularly remarkable, but I wouldn't have used it a year ago when I was first learning Haskell, so I thought someone should make note of it. There are also two important things to take away from this.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;1. You could only do this if imperative routines are treated as values. The pons asinorum that Eric S. Raymond was referring to is not without its benefits.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;2. Would an applicative instance for STM be nicer? At the least, we might be able to do code like this instead.&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       stmWait $ GroceryStore &amp;lt;$&amp;gt; a &amp;lt;*&amp;gt; b &amp;lt;*&amp;gt; c&lt;/span&gt;&lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;p /&gt;  &lt;/div&gt;  &lt;div&gt;What would be wrong with the naive implementation of this?  e.g.:&lt;/div&gt;  &lt;div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;(&amp;lt;*&amp;gt;) :: (Functor m, Monad m) =&amp;gt; m (a -&amp;gt; b) -&amp;gt; m a -&amp;gt; m b&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;(&amp;lt;*&amp;gt;) mf ma =&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;    do a &amp;lt;- ma&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       f &amp;lt;- mf&lt;/span&gt;&lt;/div&gt;  &lt;div&gt;&lt;span style="font-family: courier new, monospace;"&gt;       return $ f a&lt;/span&gt;&lt;/div&gt;  &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt; &lt;/div&gt;  &lt;div&gt;Again, I'm probably way out of my depth here, so I apologize profusely if this is asinine.&lt;/div&gt; &lt;p style="font-size: 10px;"&gt; &lt;a href="http://posterous.com"&gt;Posted via email&lt;/a&gt;  from &lt;a href="http://lambdasquirrel.posterous.com/haskell-and-stm"&gt;lambdasquirrel's posterous&lt;/a&gt; &lt;/p&gt; &lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-5325074129977977109?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/5325074129977977109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=5325074129977977109' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5325074129977977109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5325074129977977109'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/05/haskell-stm-why-no-applicative.html' title='Haskell &amp;amp; STM, Why no Applicative?'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-5345217753722603899</id><published>2010-05-05T07:51:00.000-07:00</published><updated>2010-05-05T08:59:38.067-07:00</updated><title type='text'>Academia isn't Broken.  We Are.</title><content type='html'>I saw this piece on Hacker News this morning.  It struck a chord, but something wasn't right about it.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://brucejacob.tumblr.com/post/373498114/academia-and-the-decline-of-wealth-in-america"&gt;http://brucejacob.tumblr.com/post/373498114/academia-and-the-decline-of-wealth-in-america&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;If academia is contributing to the lack of innovation in this country, then maybe it's because we expect the wrong things from academia?  I don't mean to say this as another pompous American, but when I used to chat with friends from abroad back in school, I was struck by how many of them had a uniform educational experience.  This wasn't a blanket effect and there were more than enough exceptions to produce many of the most awesome researchers I've met.  Back at home though, even the countries that had effective programs to retain their top talent suffered from a lack of innovation.&lt;br /&gt;&lt;br /&gt;By contrast, there is no standard curriculum at the top 5 US universities for CS.  But most of the kids coming out there are shills anyway.  I went to one of the good schools, and many kids (and their parents) were concerned about whether what they were learning would "prepare them for the real world".  That basically meant: did it teach you Java or consulting?  You see what's happening?  What our education system didn't do to them, their own expectations of college did, and sadly, they seem to have done it to themselves just as badly as the education system of those foreign countries did.&lt;br /&gt;&lt;br /&gt;But education isn't about churning out stamped spoons, and that's why crap like that No Child Left Behind Act bothered me so much.  Where we went wrong is that we began viewing education as something everyone is entitled to, for all the wrong reasons.  Education is not factory farming.  Steve Jobs took calligraphy because he thought it was interesting, and no one thought what the Google guys were doing was "practical".  I'll wager that the Google guys did it because it seemed like nerdy awesomeness to transform web search into a giant linear algebra problem.  Just as Academia is about exploring the boundaries of what we know, Education is about enriching one's thought process, and that's the leading source of innovation in our modern economy: good ideas from the fringe, implemented intelligently and autonomously.&lt;br /&gt;&lt;br /&gt;The entitlement of success that seems to follow from attending college is what's broken.  The expectation that you will get a cushy 9-5 job in return for that diploma is what's broken.  It in essence is a laziness of the mind, an unwillingness to chart out one's own path, the very idea of which is quite unacademic.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-5345217753722603899?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/5345217753722603899/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=5345217753722603899' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5345217753722603899'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5345217753722603899'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/05/academia-isnt-broken-we-are.html' title='Academia isn&apos;t Broken.  We Are.'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-1791128803301282190</id><published>2010-04-28T21:41:00.000-07:00</published><updated>2010-04-29T02:18:21.387-07:00</updated><title type='text'>Dirty Tricks</title><content type='html'>&lt;div&gt;&lt;p&gt;Here is a type I'm using to record stats.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;data UserzFormationViews&lt;/div&gt;&lt;div&gt;  = UserzFormationViews&lt;/div&gt;&lt;div&gt;      { formationsViewed  :: [(FormationId, UTCTime)]&lt;/div&gt;&lt;div&gt;      , ...&lt;/div&gt;&lt;div&gt;      }&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;Basically, the data is a &lt;a href="http://www.haskell.org/ghc/docs/6.12.1/html/libraries/base/Data-Monoid.html"&gt;monoid&lt;/a&gt;.  Actually, it's even less restrictive than that, because the monoidal append on this piece of data is commutative (i.e. embarrassingly parallel).  It's incredibly convenient to be able to just throw a pile of these together and tabulate the stats with a familiar &lt;code&gt;mconcat&lt;/code&gt;.&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;At other times, it's useful to get all the user's views, in a form like this:&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;class RetrieveViews a where&lt;/div&gt;&lt;div&gt;    getViews :: a -&gt; [(UserId,FormationId,UTCTime)]&lt;/code&gt;&lt;/div&gt;&lt;div&gt;&lt;p&gt;This obviously messes with the monoidal definition of UserzFormationViews.  The initial object (i.e. &lt;code&gt;mempty&lt;/code&gt;) would need a dummy value for the UserId.  In more primitive languages, you'd just leave that as NULL, which is a dirty hack.  And we don't like those kinds of dirty hacks in Haskell.  What do we do instead?&lt;/p&gt;&lt;/div&gt;&lt;div&gt;&lt;code&gt;instance RetrieveViews (UserId, UserzFormationViews) where&lt;/div&gt;&lt;div&gt;...&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;vs = getViews (zeUserzId,zeUserzViews)&lt;/code&gt;&lt;/div&gt;&lt;br&gt;&lt;div&gt;So wrong and so awesome at the same time. :)&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-1791128803301282190?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/1791128803301282190/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=1791128803301282190' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1791128803301282190'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/1791128803301282190'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/04/dirty-tricks.html' title='Dirty Tricks'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-5092767461920909558</id><published>2010-04-21T01:32:00.000-07:00</published><updated>2010-04-21T01:49:37.221-07:00</updated><title type='text'>A Problem I've Encountered with Types</title><content type='html'>&lt;div&gt;Everyone is familiar with how we can use types to encode checks into our code.  For example:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;data User&lt;br /&gt;  = SystemUser SystemProcessInfo&lt;br /&gt;  | AnonUser TimeLoggedIn&lt;br /&gt;  | RegisteredUser UserId&lt;br /&gt;&lt;br /&gt;data UserId&lt;br /&gt;  = PaidUser (..)&lt;br /&gt;  | FreeUser (..)&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;More generally, you can use &lt;a href="http://www.haskell.org/haskellwiki/Type_witness"&gt;type witnesses&lt;/a&gt; to mix together similar types in the same list, to mimic some aspects of dynamic typing.&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;h3&gt;The Problem:&lt;/h3&gt;&lt;br /&gt;&lt;div&gt;Suppose you have a type witness, such that all the witnessed types derive some typeclass (or a similar situation where you are using types to enforce behavior).  Is it possible to have the compiler automatically derive that typeclass for the type witness, i.e. something similar to GeneralizedNewtypeDeriving?  This kind of boilerplate is yucky:&lt;/div&gt;&lt;br /&gt;&lt;code&gt;data A&lt;br /&gt;  = A1 X&lt;br /&gt;  | A2 Y&lt;br /&gt;  | A3 Z&lt;br /&gt;&lt;br /&gt;instance Foo A where&lt;br /&gt;  getFoo (A1 x) = getFoo x&lt;br /&gt;  getFoo (A2 x) = getFoo x&lt;br /&gt;  getFoo (A3 x) = getFoo x&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;div&gt;One area where this problem seems unavoidable is when you have to deal with collated data of different types.  For example, say you have a list of items that were found to be complementary in terms of content, but are of different types.  In such cases, type witnesses are unavoidable.  If I can get a good solution to this problem, I'll be sure to post it.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-5092767461920909558?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/5092767461920909558/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=5092767461920909558' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5092767461920909558'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/5092767461920909558'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/04/problem-ive-encountered-with-types.html' title='A Problem I&apos;ve Encountered with Types'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-725645457693037552</id><published>2010-04-09T01:41:00.000-07:00</published><updated>2010-04-09T03:09:56.844-07:00</updated><title type='text'>Lazy IO with Haskell Monads</title><content type='html'>&lt;div&gt;Haskell's treatment of imperative programming and side effects is possibly the most derided feature of the language.  As someone who's written desktop apps, I'm certainly aware of the inflexibility that Haskell's sandboxing imposes.  However, monads happen to mesh very nicely with Haskell's purity and laziness, and what they take away, they give back in other ways.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Suppose for example, you are designing an evil robot that goes out and steals wheels from people's cars.  The robot can steal up to 4 wheels from a car, but because it tries to avoid being detected by witnesses (organic or otherwise), it may abort the job prematurely.  You need it to fetch 20 wheels a night.  No more, no less.  Fewer, and you may not be able to pay the bills.  More, and the police might start catching on.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;For this simple example, you have a function that returns a monadic value:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;stealWheelz :: Coordinates -&gt; IO [Wheel]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Then you have some other pre-calculated list of random locations that you want the robot to steal from.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;locations :: [Coordinates]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Now here's the funky part.  You can define a function takeM, as such:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM :: (Monad m) =&gt; Int -&gt; [m [a]] -&gt; m [a]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM = takeM' []&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM' :: (Monad m) =&gt; [a] -&gt; Int -&gt; [m [a]] -&gt; m [a]&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM' acc 0 xs = return acc&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM' acc n [] = return acc&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM' acc n (x:xs) =&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;    do rs &lt;- x&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;       let rs' = take n rs&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;           n' = n - length rs'&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;       takeM' (acc ++ rs') n' xs&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and then your list of tires stolen can simply be:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;takeM 20 (map stealWheelz locations)&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;With this code, the robot will only steal as many tires is as necessary, even if the list of coordinates is of infinite length.  Because Haskell is lazy, and IO routines (and all imperative programming that are modelled as monads) are treated as lazy values, you can pass around tasks, with all their arguments bound--even in a strict monad like IO--, and not have to deal with a lot of the usual glue that goes into determining how many results to return.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Btw, that means you can actually pass around the value:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;let stealSomeWheelz = map stealWheelz locations&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;and take results from that list of actions only as you need them.  This sort of thing is doable, but *much* less elegant in languages that do not treat actions as if they were values.  When you design a language to operate via side effects, then you have to deal with those side effects immediately, as you arise.  That means you can't easily reason about it at a higher level, even when you're trying to do simple things like "take the first n results".&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;As an example, I can apply a filter function to those results, as such:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;-- Police commissioner is in town tonight with his Escalade&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;let stealSomeWheelz = map stealWheelz locations&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-family:'courier new';"&gt;&lt;span class="Apple-style-span"  style="font-size:small;"&gt;filter noCaddyWheelzTonight &lt;$&gt; stealSomeWheelz&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I discovered this trick when I needed to sanitize the first n queries for a particular area of interest, given a statically-ranked listed of sources.  In a more general setting, removing the glue from imperative programming means that I can focus more on what I'm doing, rather than what I'm programming.  That's a good thing.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I'd love to see more gems like this.  I'm sure someone else has discovered this already, it's in a library somewhere, and I'm just yakking the obvious.  I have a feeling that the functional community (and the rest of the world by proxy) is only beginning to discover the value of treating imperative routines as if they were monadic values.  Indeed, at the time of this writing, there's a &lt;a href="http://defn.blip.tv/file/3461134/"&gt;video on HN concerning monads in Clojure&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/3601356092114855287-725645457693037552?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/725645457693037552/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=725645457693037552' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/725645457693037552'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/725645457693037552'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/04/lazy-io-with-haskell-monads.html' title='Lazy IO with Haskell Monads'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-7024135511600697015</id><published>2010-03-31T02:07:00.000-07:00</published><updated>2010-03-31T11:55:15.345-07:00</updated><title type='text'>Reviving Post-Modern Journalism</title><content type='html'>&lt;div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Or, why newspapers aren't making money anymore.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;1997 was a different time.  I remember seeing all the adults on the subway with their newspapers in hand.   Back then, in New York, the newspaper you read said something about you.  The regular Joes read the Daily News or the Post, depending on their political slant.  These were entertaining tabloids that slightly enhanced the truth, and you could tell just by reading the headlines.  The folks who considered themselves somewhat more educated would have in hand a copy of the New York Times or the Wall Street Journal.  It was harder to detect bias in those papers, but you could certainly discern it if you knew the raw facts and the spectrum of viewpoints.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Just as importantly, you could tell immediately which newspaper was which, just by looking at them.  In the case of the plebeian pubs, the headlines were typed with screaming 2-inch high font.  The patrician pubs used starkly different and recognizable typefaces for their titles.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Today, most newspapers in America are going out of business, and one thing that's perhaps been overlooked was the status conferred by reading a newspaper.  One of the oldest adages in marketing states that the magnitude of status or identity conferred by a product determines how many brands you'll have of it.  There are two major brands of toothpaste, as far as I can tell.  People don't take too much pride in their toothpaste.  You can't tell if someone brushed with Crest or Colgate, only whether they did at all.  On the other hand, there's dozens of different car brands.  Cars are expensive.  They signal immediately one's level of wealth and some brands alert others to the owner's hobbies, or the size of the owner's beer gut or phallic insecurities.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;No one really read the news just for the sake of knowing.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;So how does this relate to newspapers?…  It's quite simple:  What if they don't confer status or identity anymore?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;There's more than one take on this.  My middle school math team teacher, a fairly well educated and openly intellectual person, once lamented how there were more newspapers and viewpoints in his day.  He was born just before America suburbanized in the 50s, 60s and 70s.  Sprawl was the first thing that happened.  People may only see the newspaper on your lawn for a second in the morning, if at all.  Next came computers, phones and tablets.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The problem with the modern world is that it's just not possible for others to see what you are reading anymore.  What are they going to do?  Squint at your laptop to see what you're reading?  Forget about trying to surreptitiously read off an iPhone.  You could argue that it can be done, but what's important is that people don't expect those around them to do so.  Most damningly, most news in a paper is from the AP or Reuters anyway.  It's just a piece of text and it really doesn't matter then where you get it from.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The other thing that happened is that the newspaper has stopped being a marker for appearing intelligent and well-informed.  Old folks read newspapers.  The well-informed folks get their news off the wire, on their smartphone, 30 seconds after Reuters or the AP pushed it out.  What's post-modern journalism to do in the face of this?&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span"  style="font-size:large;"&gt;Journalism needs to be "interesting" again, and other silly proposals.&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I think that whatever journalism survives this new age will have to branch out again.  It needs to once again appeal to people's inclinations and identity.  Perhaps that's why blogs are so popular these days.  They provide "analysis" alongside content.  There are some news sources that seem to understand this.  Stratfor, for example, provides a well-reasoned realpolitik attitude towards world news, and combines it with a solid understanding of local history and politics.  It should be emphasized that unless you're aiming to be the 800lb gorilla like Fox News, your core readers should be willing to pay for your news.  Everyone's talked about how the Internet has allowed companies to exploit niche markets.  Perhaps it actually requires it, in our new world of commoditized information.  Specialize.  That's only part of the puzzle though.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;The next part of the puzzle may be difficult for old media to stomach.  They need to let subscribers share their material.  If buying a newspaper was a way to confer status, then they can revive the dynamic in the modern world by letting subscribers mail a limited number of pieces to an unlimited number of their friends.  Chances are, these friends aren't going to read the piece at all.  What matters though is that subscriber will pay for a news service that tells others about how they think the world should be seen.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Sharing would also be a way for a subscription service to spread virally.  People should also be able to post links to these articles on some social network, where they would be able to give props for them.  People get a buzz out of seeing that others agree with their viewpoint, or found an interest in something that they read off the wire.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;I actually think there's room on the web for a news service tailored exactly for this purpose (or maybe even more), especially if such a service were to aggregate based on people's interests and viewpoints.  Implementing such a thing would of course be no trivial matter, but seeing how the incumbents seem to have dropped the ball, the time seems right.  It could be monetized as well.  The service could form a symbiosis with the news media by helping them sell subscriptions.&lt;/div&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-7024135511600697015?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/7024135511600697015/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=7024135511600697015' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/7024135511600697015'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/7024135511600697015'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2010/03/reviving-post-modern-journalism.html' title='Reviving Post-Modern Journalism'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-6556230869126220319</id><published>2008-07-04T22:07:00.000-07:00</published><updated>2008-12-10T19:07:34.009-08:00</updated><title type='text'>Études en OCaml:  Keeping your functions clean, Pt 2</title><content type='html'>&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Long, non-atomic functions are the bane of functional languages&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;For reasons I don't completely understand (but will try to discuss anyway), functional languages seem to raise the bar for code quality. In the interest of making life more exciting, functional languages also pile on the rewards when you do it right, and they'll conversely pie you in the face when you get it wrong.&lt;br /&gt;&lt;br /&gt;You can accomplish a lot in a few lines of OCaml code, especially if what you're doing is well-suited to the functional model, and this creates special challenges for folks coming from C/C++. The tuple and variant matching features of the language make it fun and easy to violate separation of layers. C programmers will especially be delighted that their functions look so clean and short (only 20 lines!), and yet accomplish so much!&lt;br /&gt;&lt;br /&gt;Alas, the actual usage of the function will inevitably be ugly, and you won't find that out until much later, when you have to refactor that 20 line function down to one or two wrapper functions and two or three 5-10 line functions. The problem with long functions is that it's difficult to reuse them, especially with the bread and butter fold_left and map functions. I hate to use buzzwords but I think it's accurate to say that your functions need to be *agile*.&lt;br /&gt;&lt;br /&gt;The very idea of this starkly contrasts with how we write code in C/C++. Those primitive stone age tools limit how short one can practically write a function; the lack of built-in support for tuples and abstract datatypes means that the programming overhead of passing return values (via pointer arguments and structs) is fairly high.&lt;br /&gt;&lt;br /&gt;As such, abusing the language is normal and expected for OCaml beginners, especially those coming from the imperative domain, so don't fret if you find yourself rewriting functions so that they're shorter. It is happening because you are learning.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Tools for writing clean functions&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;You can't truly fix a problem until you know why it happens, yes? If it's true that our predisposition for the detail-oriented is what keeps us from writing clean functions, then perhaps the fix is one of the oldest in the book: Think before you hack. If you're not scoffing, then here is one idea for abetting this. If you're not exactly sure what you're doing, write a comment-- one phrase --to describe what you want to do before you start writing your code. If you need another phrase, then you need another function.&lt;br /&gt;&lt;br /&gt;I've collected a number of thoughts-- more concrete ones --that have also helped me when I was learning OCaml, and I hope you find them useful as well.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_NEw4Si59C7A/SHy0KZIcwsI/AAAAAAAAAAU/q72L3tmrduw/s1600-h/300px-Mandel_zoom_00_mandelbrot_set.jpg"&gt;&lt;img style="margin: 0pt 0pt 10px 10px; cursor: pointer;" src="http://4.bp.blogspot.com/_NEw4Si59C7A/SHy0KZIcwsI/AAAAAAAAAAU/q72L3tmrduw/s320/300px-Mandel_zoom_00_mandelbrot_set.jpg" alt="" id="BLOGGER_PHOTO_ID_5223247758480949954" border="0" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;/div&gt;&lt;div style="text-align: center;"&gt;&lt;span style="font-size:85%;"&gt;I have a hunch that clean code is not unlike a fractal...&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;OCaml-specific rules&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;- The broad 25-line rule&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I pulled 25 out of my ass actually, but that's not really the point. The point of this exercise is to give beginners an idea of what OCaml code should look like. Readable OCaml code is typically composed of 5-20 line functions, or larger functions that are composed of subfunctions that are 3-13 lines long (assuming of course that you have spaces in between and not all 13 lines are actually code). Dispatches will be longer, but should not contain any logic of their own.&lt;br /&gt;&lt;br /&gt;There will be many exceptions to this rule, particularly with purely imperative code like numerical computations, gui dispatchers and sysadmin-like tasks. OCaml has attracted a lot of numerical folks to its side and those jerks often like to remind me that none of my rules for keeping my code clean apply to them. It's important to identify purely imperative tasks like numerics, because they typically result in long functions no matter what you do. Once you have them identified, you can confine them into their own functions so that they won't muddle the rest of your code.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;- Follow the types that you declare as layers of separation&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;The same H-M variant types that grant OCaml its incredible expressiveness are also useful guidelines for determining how you should write your functions. Fortunately for us, it's much easier to think in terms of what you want to hold in a type than it is to figure out where a function should begin and where it should end. In a nutshell, your functions may directly match against a particular type, but they shouldn't descend into the members of those types.&lt;br /&gt;&lt;center&gt;&lt;span style="font-family:courier new;"&gt;&lt;table align="top"&gt;&lt;tbody&gt;&lt;tr align="top"&gt;&lt;td align="top"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Good:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;type entity =&lt;br /&gt; metadata *&lt;br /&gt; geometric_primitive&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;let render_geo_prim gp =&lt;br /&gt; match gp with&lt;br /&gt;   TRIANGLE (a,b,c) -&gt;  ...&lt;br /&gt;&lt;br /&gt;let render_entity (md,gp) =&lt;br /&gt; render_geo_prim gp&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;td valign="top"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Bad:&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;type entity =&lt;br /&gt; metadata *&lt;br /&gt; geometric_primitive&lt;br /&gt;&lt;br /&gt;...&lt;br /&gt;&lt;br /&gt;let render_entity (md,gp) =&lt;br /&gt; match gp with&lt;br /&gt;   TRIANGLE (a,b,c) -&gt;  ...&lt;br /&gt;&lt;/td&gt;&lt;br /&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;br /&gt;&lt;/span&gt;&lt;/center&gt;&lt;br /&gt;&lt;br /&gt;I've tried applying this methodology at the module level. In a general sense, one could try to avoid descending into types that aren't declared in that module. I'm not sure if this works. Consider the following example. You have a graphics program. In this graphics program you have a type definition for the entities you want to draw, e.g. triangles, spheres, lines, meshes, etc. For the renderer you want the program to support a GL mode and a realtime-raytraced mode. Putting all of the code into the same file with the type definition would be a gross violation of layers, and will likely result in a single source file that'll be well over 100kb in size.&lt;br /&gt;&lt;br /&gt;There are some types that you will want to expose the internals of. I term these types interface-types. Then there are some types that you expect to grow in the future, in ways that will totally mess with the pattern matching when you change the type spec.  You typically want to hide the representations of the latter types, or perhaps consider using records instead of tuples.  You can do this by writing a custom .mli header file for your source file, and then erasing the right hand side of the type definition.  An easy way to do this is to pipe the output of `ocamlc -i`:&lt;br /&gt;&lt;span style="font-family:courier new;"&gt;&lt;br /&gt;ocamlc -i blah.ml &gt; blah.mli&lt;br /&gt;&lt;br /&gt;&lt;center&gt;&lt;table align="top"&gt;&lt;tbody&gt;&lt;tr align="top"&gt;&lt;td align="top"&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;blah.ml:&lt;/span&gt;&lt;br /&gt;type stuff = wakka * float * int * string&lt;br /&gt;&lt;br /&gt;&lt;/td&gt;&lt;td&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;blah.mli:&lt;/span&gt;&lt;br /&gt;type stuff (* hide actual definition *)&lt;br /&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/center&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;font-size:130%;" &gt;Stuff that applies to OCaml and programming in general&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;-Resist any impulse to inline your code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;I've heard many experienced and smart programmers tell me that I should inline a function because it's only got one caller. DO NOT DO THIS. Unless you are writing numerical computations or GL rendering routines, you *will* want the shorter function to List.map or Something.iter at some later point.&lt;br /&gt;&lt;br /&gt;The jury is undecided on this in the realm of general programming. Although there are many good programmers who've told me that it's silly to split functions up, the best C/C++ programmers I know will typically do so. However, I care little for arguing how things are done with ancient fossils like C, so I leave the general applicability of this rule up to the reader.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;- No more than 4 arguments for any given function&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;Why four? Cognitive psychologists have known for some time that people have a short term memory buffer of size 7, give or take 2.  I'm sure many programmers will have the "max" of 9 (more if they've got Asperger's or autism which is perfectly possible), but you don't want your code to be only readable to the freaks (like yourselves) with photographic memory.  Pushing the limits of your coworkers' memory isn't nice.  Kindly leave them a free register.&lt;br /&gt;&lt;br /&gt;"But I can't do with less than 5 independent arguments...", you say! If you *need* more than 4 independent, unrelated arguments for a function, it's possible that you need to write whatever it is you are doing in OO. If you need more than 4 arguments and they are not independent/unrelated, then perhaps you should be passing those values around as a tuple or as a record. I've found it helpful to try to understand why the OCaml designers implemented records, when there already tuples in the language. Functors are also sometimes useful for making code readable, and for keeping the argument count down.&lt;br /&gt;&lt;br /&gt;It's not a bad idea to apply this analysis elsewhere. In OCaml, 1 line of code will often express 1 routine, as opposed to C, which often requires 10-20 lines to do something like traverse a list of any sort (even using library functions). Thus it's practical to have many functions that are only 3-7 lines long in OCaml.&lt;br /&gt;&lt;br /&gt;Note that you'll have to amend this rule for older languages like C, where we commonly pass around 2-3 arguments that we barely need, because the language does not support tuples or OOP.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;- No getters for the OO code&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;People with C++ and Java experience will revulse in horror at the idea that you can't make a class variable public, or even protected.&lt;br /&gt;&lt;br /&gt;Having written OO code in several languages for some time now, I'm convinced that C++ and Java need to expose their class implementations and member variables because they lack functional expressiveness (e.g. tuples, abstract primitive datatypes, first class functions). In fact, one of the greatest epiphanies I've had came after I read that you generally should not have any getters at all.  Try to do everything locally, without exposing any variables.&lt;br /&gt;&lt;br /&gt;Ironically, I read the no-getters rule in a Python article somewhere, which itself sourced the tactic to an unnamed Java article! The idea applies to OCaml all the same. Not using any getters lives up to the spirit of what the OCaml OO restrictions are trying to accomplish: proper separation of layers in your OO code.&lt;br /&gt;&lt;br /&gt;There will be corner-cases where the no-getters rule doesn't apply, but it's surprising how far you can get with this practice, and how much it improves your code.  It also seems to be possible to shove all the variables that need getters into a separate class, usually called something like "SettingsForBlah".&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-6556230869126220319?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/6556230869126220319/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=6556230869126220319' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/6556230869126220319'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/6556230869126220319'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2008/07/tudes-en-ocaml-keeping-your-functions.html' title='Études en OCaml:  Keeping your functions clean, Pt 2'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://4.bp.blogspot.com/_NEw4Si59C7A/SHy0KZIcwsI/AAAAAAAAAAU/q72L3tmrduw/s72-c/300px-Mandel_zoom_00_mandelbrot_set.jpg' height='72' width='72'/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-3601356092114855287.post-7844101004051277698</id><published>2008-06-30T14:08:00.000-07:00</published><updated>2008-12-10T19:07:34.630-08:00</updated><title type='text'>Études en Ocaml:  Keeping your functions clean, Pt 1</title><content type='html'>&lt;span style="font-weight: bold;font-size:130%;" &gt;"But you could save a PUSH instruction if you inlined it..."&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_NEw4Si59C7A/SIV012hmMrI/AAAAAAAAAAk/OfYdN_rEvgc/s1600-h/butterfly_small.jpg"&gt;&lt;img style="margin: 0pt 10px 10px 0pt; float: left; cursor: pointer;" src="http://1.bp.blogspot.com/_NEw4Si59C7A/SIV012hmMrI/AAAAAAAAAAk/OfYdN_rEvgc/s320/butterfly_small.jpg" alt="" id="BLOGGER_PHOTO_ID_5225711411151647410" border="0" /&gt;&lt;/a&gt;One of my coworkers, who is still somewhat fresh out of college, asked me why I had broken up one of my functions into a few smaller ones, when there was only one caller for each of them. One of the funnier things he suggested was that inlining the code would save an x86 push instruction. But then he surprised me, by suggesting that unnecessarily breaking up functions can make code more difficult to read.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;span style="font-size:130%;"&gt;&lt;span style="font-weight: bold;"&gt;Why is it so hard to keep functions short?&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;It's hard to keep functions short. If you do not think so, then you are probably lucky, or smart, or perhaps it isn't too difficult for you after years of hacking code, but that doesn't make it any less inherently difficult. It is still useful to understand why other people find it difficult to keep functions short. Indeed, why is it difficult at all?&lt;br /&gt;&lt;br /&gt;Before we continue, I should point out that it's better to say that functions should be "atomic", or "clean". A good function is one that can't logically be broken down anymore without making it pointless. This small but important semantic difference has significance later on.&lt;br /&gt;&lt;br /&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_NEw4Si59C7A/SIVyEkqLToI/AAAAAAAAAAc/JbZunqxNq8w/s1600-h/TreeForest.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://1.bp.blogspot.com/_NEw4Si59C7A/SIVyEkqLToI/AAAAAAAAAAc/JbZunqxNq8w/s320/TreeForest.jpg" alt="" id="BLOGGER_PHOTO_ID_5225708365518950018" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;What do you see here?&lt;/span&gt;&lt;br /&gt;&lt;/div&gt;&lt;span style="font-size:85%;"&gt;&lt;br /&gt;&lt;/span&gt;I'm going to make a grand, sweeping assertion that many of you will likely say "duh" to. If you disagree, then it's probably because it doesn't apply to you, and that's great but we're trying to figure out why keeping functions clean and short is difficult for most programmers-- including myself --, so please bear with me.&lt;br /&gt;&lt;br /&gt;Programmers are by and large detail-oriented. At the least, we're good at details, because we have to be. Computers are finicky contraptions that break unless everything is exactly correct. There is no "almost works" in much of what we do. Because of their digital and binary nature, computers and the tools we use to program them are not fault tolerant. It is left to the programmer to make sure everything is right, and because of this, anyone who does not enjoy picking apart the details of a problem probably won't enjoy programming.&lt;br /&gt;&lt;br /&gt;So how did I come to this conclusion? It's quite simple. Back in school, we had two pretty darn tough "weed-out" courses. One course was taught in a high level language, and the other course was taught in C and assembly. Sounds like *your* university doesn't it? Now let me ask you real quick, did the majority of your CS friends find the C/Assembly class easier, or did they totally pwn that Scheme/Lisp/SML/Haskell class? Which one did they like more? Most importantly, which one was regarded as "more practical"?&lt;br /&gt;&lt;br /&gt;Our undergraduate advisors noted that people generally found the C/Assembly class easier. Most CS students also liked that class more. The ones who didn't usually went on to grad school, which serves to further skew the pool of industry programmers&lt;span style="font-size:100%;"&gt; in the direction of the detail-oriented.&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;Programmers in industry who maintain others' code are subjected to an additional set of biases. It takes some time to learn to read code, and reading code is a bottom-up process, especially if the said code is written poorly (now isn't it funny the way that *everyone* works somewhere where the code sucks?).  If you're new to the field (like my coworker) and you're still plying the code line-by-line, it wouldn't seem that there'd be any point to breaking functions up at all. What's more is that sometimes people break up functions without adding any atomicity to the structure of their code.&lt;/span&gt;&lt;br /&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;Since programmers are detail-oriented people, writing atomic functions is not something that comes naturally because we do not typically encounter our problems from the top down. This is especially true if we learned to program in a low level, iterative language like C. Writing clean, atomic functions requires you to understand consciously what it is you are trying to do, at a high level.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;div style="text-align: center;"&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_NEw4Si59C7A/SIV3l_PHC4I/AAAAAAAAAAs/Vqevpkbfhvc/s1600-h/madrone.jpg"&gt;&lt;img style="margin: 0px auto 10px; display: block; text-align: center; cursor: pointer;" src="http://2.bp.blogspot.com/_NEw4Si59C7A/SIV3l_PHC4I/AAAAAAAAAAs/Vqevpkbfhvc/s320/madrone.jpg" alt="" id="BLOGGER_PHOTO_ID_5225714437147003778" border="0" /&gt;&lt;/a&gt;&lt;span style="font-size:85%;"&gt;A tree or a forest?&lt;/span&gt;&lt;br /&gt;&lt;div style="text-align: left;"&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;span style="font-size:100%;"&gt;But many programmers don't consciously know what they're trying to do. They just hack towards a solution and somehow, magically, a working piece of code appears, both to their benefit and to their detriment.&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;span style="font-size:100%;"&gt;&lt;br /&gt;The awesome and frightening conclusion that we gather from this is that it is hard for many of us to write clean code simply because we *can* hack code. Our ability to meticulously design algorithms, to read and hack other people's code (often at a line by line basis), to find needles in haystacks (debugging, anyone?), and perhaps our own personalities --these things are what made us into programmers in the first place. Details matter: above all, the code must work! "We can worry about how messy it is after we ship. ;)"&lt;br /&gt;&lt;br /&gt;But these traits predispose us to a mindset where we do not see our problems in the big picture sense that is useful for writing clean/atomic functions, writing and using black boxes, and maintaining a separation of layers. &lt;/span&gt;&lt;span style="font-size:100%;"&gt;Indeed, the fact that we're told that we should write "short" functions is indicative of this mindset. Shortness has little semantic meaning. It is a detail, a direct metric, not an overarching goal like "cleanliness".&lt;br /&gt;&lt;span style="font-size:78%;"&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/3601356092114855287-7844101004051277698?l=curryhoward.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://curryhoward.blogspot.com/feeds/7844101004051277698/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=3601356092114855287&amp;postID=7844101004051277698' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/7844101004051277698'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/3601356092114855287/posts/default/7844101004051277698'/><link rel='alternate' type='text/html' href='http://curryhoward.blogspot.com/2008/06/learning-ocaml-keeping-your-functions.html' title='Études en Ocaml:  Keeping your functions clean, Pt 1'/><author><name>Arthur</name><uri>http://www.blogger.com/profile/04882682450471910735</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_NEw4Si59C7A/SIV012hmMrI/AAAAAAAAAAk/OfYdN_rEvgc/s72-c/butterfly_small.jpg' height='72' width='72'/><thr:total>0</thr:total></entry></feed>
