<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>gimboland</title>
	<atom:link href="http://gimbo.org.uk/blog/feed/" rel="self" type="application/rss+xml" />
	<link>http://gimbo.org.uk/blog</link>
	<description>8 years of rambling and mumbling</description>
	<lastBuildDate>Wed, 24 Feb 2010 14:18:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Want to download music made by me? Well, now you can.</title>
		<link>http://gimbo.org.uk/blog/2010/02/24/want-to-download-music-made-by-me-well-now-you-can/</link>
		<comments>http://gimbo.org.uk/blog/2010/02/24/want-to-download-music-made-by-me-well-now-you-can/#comments</comments>
		<pubDate>Wed, 24 Feb 2010 14:09:08 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[gimbo]]></category>
		<category><![CDATA[music]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2593</guid>
		<description><![CDATA[As of a few minutes ago, you can download free mp3s of music made by me via Combinator&#8217;s page on last.fm.  (You could listen online since October 2008, but I&#8217;m 99% sure &#8220;free download&#8221; wasn&#8217;t an option at that point.)

Or if you prefer, how about a 200MB zip containing it all &#8212; plus some [...]]]></description>
			<content:encoded><![CDATA[<p>As of a few minutes ago, you can download free mp3s of music made by <strong>me</strong> via <a href="http://www.last.fm/music/Combinator">Combinator&#8217;s page on last.fm</a>.  (You could listen online <a href="http://gimbo.org.uk/blog/2008/10/28/for-your-listening-pleasure/">since October 2008</a>, but I&#8217;m 99% sure &#8220;free download&#8221; wasn&#8217;t an option at that point.)</p>

<p>Or if you prefer, how about <a href="http://www.cs.swan.ac.uk/~csandy/music/Combinator-20100224.zip">a 200MB zip containing it all</a> &mdash; <strong>plus</strong> some recent even-more-half-baked stuff which hasn&#8217;t made it to last.fm yet.</p>

<p>Go! Listen! Scrobble!</p>

<p>Somewhat vexingly, there appears to be music by someone other than me doing the rounds but tagged as &#8220;Combinator&#8221; in the artist field: some of the top-listened tracks on the Combinator page aren&#8217;t by me!  Come on, adoring public, together we can right this wrong.</p>

<p>Enjoy!</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2010/02/24/want-to-download-music-made-by-me-well-now-you-can/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Simple Observers in Haskell</title>
		<link>http://gimbo.org.uk/blog/2009/11/12/simple-observers-in-haskell/</link>
		<comments>http://gimbo.org.uk/blog/2009/11/12/simple-observers-in-haskell/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 00:37:47 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[functional-programming]]></category>
		<category><![CDATA[guis]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[wx]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2551</guid>
		<description><![CDATA[I&#8217;ve just uploaded version 0.0.1 of the simple-observer package to hackage, the Haskell package repository.

This is an implementation of the Observer design pattern in Haskell.  I am not the originator or even main author of the code in this package; that is Dutch computer scientist Bastiaan Heeren, who wrote the original as part of [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just uploaded version 0.0.1 of the <a href="http://hackage.haskell.org/package/simple-observer">simple-observer</a> package to hackage, the Haskell package repository.</p>

<p>This is an implementation of the <a href="http://en.wikipedia.org/wiki/Observer_pattern">Observer design pattern</a> in Haskell.  I am not the originator or even main author of the code in this package; that is Dutch computer scientist <a href="http://people.cs.uu.nl/bastiaan/">Bastiaan Heeren</a>, who wrote the original as part of <a href="http://www.cs.uu.nl/wiki/bin/view/Afp0607/ExerciseWXHaskell">an exercise for some students</a>.  But recently I was doing some GUI programming with <a href="http://haskell.org/haskellwiki/WxHaskell">wxHaskell</a> (which I&#8217;ve found to be great, by the way) and found myself hankering for an observer or something MVC-ish, and my googling led me to his code.  I used it, and then thought it might be worth releasing to the world at large &mdash; particular as it&#8217;s <i>not</i> wx-specific, or even GUI-specific, really.  Bastiaan tells me he&#8217;s happy for me to do so, so here it is.  I&#8217;ve changed names, separated it into two modules, and replaced <tt>IORef</tt> with <tt>MVar</tt>s in order to better support multi-threaded use &mdash; but at heart it&#8217;s identical to Bastiaan&#8217;s code.</p>

<p>The basic idea is that an observable is a piece of mutable state, and when it&#8217;s changed, a list of observer functions are called in sequence, and passed the new value.  For wx programming &ndash; which is anyway quite stateful and not very idiomatically functional &ndash; I&#8217;ve found it to be quite effective.  Here&#8217;s a small example which illustrates basic use&#8230;</p>

<p>My GUI has a start/stop button, which toggles a <tt>running</tt> flag.  When <tt>running</tt> is true, the button says &#8220;stop&#8221;, and certain things happen in the app&#8217;s idle handler (to run whatever is supposed to be running); when <tt>running</tt> is false, the button says &#8220;start&#8221;, and certain <i>other</i> things happen in the app&#8217;s idle handler.  So here&#8217;s how we set it up:</p>

<p>In my app&#8217;s setup phase, I create <tt>running</tt>, which is initially false, using <tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer-Synchronous.html#v%3AcreateSub">createSub</a> :: a -> IO (Sub a)</tt>:</p>

<pre><code>    running &lt;- createSub False
</code></pre>

<p>Later on (actually in a different function, which receives <tt>running</tt> as a parameter), I create the start/stop button and use <tt>running</tt>&#8217;s current value to initialise its appearance:</p>

<pre><code>     r &lt;- getValue running
     btnRunStop &lt;- button p [text := runStopBtnTxt r, on command := runStopClicked running]
</code></pre>

<p>Here, <tt>runStopBtnTxt :: Bool -> String</tt> just returns &#8220;start&#8221; or &#8220;stop&#8221; appropriately.  We use it elsewhere, which is why it&#8217;s factored out.  When the button is clicked, <tt>runStopClicked</tt> toggles the state of <tt>running</tt> (and does other stuff not shown here):</p>

<pre><code>    runStopClicked :: Sub Bool -&gt; -&gt; IO ()
    runStopClicked running = do r &lt;- getValue running
                                running `setValue` not r
</code></pre>

<p>(This would actually be neater using <tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer.html#v%3AchangeValue">changeValue</a> :: Sub a -> (a -> a) -> IO ()</tt>, but in the real version I use <tt>r</tt> later on, so this I need the <tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer.html#v%3AgetValue">getValue</a></tt> anyway.)</p>

<p>So this <tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer.html#v%3AsetValue">setValue</a></tt> call will cause all of <tt>running</tt>&#8217;s observers to be called with <tt>not r</tt>.  The last thing we should do, then, is attach an observer:</p> 

<pre><code>    addObserver running (\x -&gt; btnRunStop `set` [text := runStopBtnTxt x])
</code></pre>

<p><tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer.html#v%3AaddObserver">addObserver</a> :: Sub a -> (a -> IO ()) -> IO ()</tt> takes an observable subject and an observer function, and attaches that function to the subject&#8217;s list of observers.  Here, the observer function just updates the text.</p>

<p>(It&#8217;s worth noting that the observer&#8217;s type is <tt>a -> IO ()</tt> <i>not</i> <tt>Sub a -> IO ()</tt> &mdash; i.e. observers receive values, not subjects.  The subtext is that an observer shouldn&#8217;t modify the subject it&#8217;s observing, lest ye loop infinitely; you can get round this by passing the subject proper as an earlier argument, and provided it used <tt><a href="http://hackage.haskell.org/packages/archive/simple-observer/0.0.1/doc/html/Control-Observer.html#v%3AsetValue%27">setValue'</a></tt> not <tt>setValue</tt> you&#8217;d be fine &mdash; but I don&#8217;t know of any reason why you&#8217;d want to do this.)</p>

<p>The first win here is that the button&#8217;s <tt>on command</tt> function doesn&#8217;t need the button as a parameter, because it&#8217;s not directly updating the button text.  The deeper win is relatively cheap and clean separation of concerns: the button only toggles the <tt>running</tt> value, and (separately) stuff happens when <tt>running</tt> changes.  If some other mechanism (eg some network event) could also cause <tt>running</tt> to change, we&#8217;d already be dealing with it The Right Way: just add another observer.  Without observers, if our reaction code was in the button&#8217;s <tt>on command</tt> handler, we&#8217;d need to call that, or factor the reaction code out, in order to deal with it then.  This way&#8217;s clearly nicer.  But hey, you&#8217;re reading a blog post containing type signatures, so I presumably don&#8217;t really <i>need</i> to explain separation of concerns, or the observer pattern, to you.  :-)</p>

<p>I&#8217;m aware that there are more sophisticated approaches to this problem.  I&#8217;m reliably informed that <a href="http://en.wikipedia.org/wiki/Functional_reactive_programming">Functional Reactive Programming</a> (FRP) subsumes observer quite naturally, but I don&#8217;t understand it enough to comment.  Tom Lokhorst <a href="http://www.haskell.org/pipermail/haskell-cafe/2009-November/068915.html">tells us</a> that Erik Meijer &#038; Co. at Microsoft have a good handle on this, <a href="http://channel9.msdn.com/shows/Going+Deep/Expert-to-Expert-Brian-Beckman-and-Erik-Meijer-Inside-the-NET-Reactive-Framework-Rx/">as discussed in this entertaining video</a>.  Alternatively, if we like message-passing as our basic computational model, <a href="http://chplib.wordpress.com/2009/11/10/the-observer-pattern-using-a-message-passing-process/">an implementation in CHP</a> might be just the ticket &mdash; and that certainly looks like an impressively powerful approach.  However, in my case, I wanted to keep things in a single thread as much as possible, because Haskell&#8217;s GUI frameworks (and indeed wx across all languages?) seem to interact with multi-threading in non-simple manners.  This is also pretty much why I decided <i>against</i> implementing <a href="http://www.haskell.org/pipermail/haskell-cafe/2009-November/068891.html">Neil Brown&#8217;s suggestion</a> that the observers should be run in their own threads.  Of course, if an observer wants to fork a thread, it absolutely can, and I may find myself doing this in my app soon &mdash; but I didn&#8217;t quite see the utility of baking it in.  That&#8217;s probably my sequential imperative background showing through, and hopefully one day I&#8217;ll shake it off and welcome our new, multi-threaded masters.  To conclude, everything mentioned in this paragraph is why I decided to release this as <i>simple</i>-observer.</p>

<p>Anyway, hopefully somebody will find this useful.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/11/12/simple-observers-in-haskell/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Maintenance time</title>
		<link>http://gimbo.org.uk/blog/2009/11/10/maintenance-time/</link>
		<comments>http://gimbo.org.uk/blog/2009/11/10/maintenance-time/#comments</comments>
		<pubDate>Tue, 10 Nov 2009 14:32:43 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[gimboland]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2544</guid>
		<description><![CDATA[I&#8217;m going to be doing some Gimboland maintenance over the next couple of days/weeks, so if things disappear or go doolally, that&#8217;s why.  Ta!]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to be doing some Gimboland maintenance over the next couple of days/weeks, so if things disappear or go doolally, that&#8217;s why.  Ta!</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/11/10/maintenance-time/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Coders At Work: Simon Peyton Jones</title>
		<link>http://gimbo.org.uk/blog/2009/10/01/coders-at-work-simon-peyton-jones/</link>
		<comments>http://gimbo.org.uk/blog/2009/10/01/coders-at-work-simon-peyton-jones/#comments</comments>
		<pubDate>Thu, 01 Oct 2009 17:14:00 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2532</guid>
		<description><![CDATA[
I see it as, when the limestone of imperative programming is worn away, the 
granite of functional programming will be observed.
Simon Peyton Jones


(I&#8217;m still not quite sure why I wrote this.  You should just go and buy the book.  But maybe someone will be interested.)

I got my copy of Peter Seibel’s new book [...]]]></description>
			<content:encoded><![CDATA[<blockquote>
<p>I see it as, when the limestone of imperative programming is worn away, the 
granite of functional programming will be observed.</p>
<p class="attribution">Simon Peyton Jones</a>
</blockquote>

<p>(I&#8217;m still not quite sure why I wrote this.  You should just go and buy the book.  But maybe someone will be interested.)</p>

<p>I got my copy of Peter Seibel’s new book <a href="http://www.codersatwork.com/">Coders At Work</a> yesterday, and the first chapter I turned to was, naturally, the interview with <a href="http://research.microsoft.com/en-us/people/simonpj/">Simon Peyton Jones</a>. I found it to be excellent and informative; of course, as anyone who’s seen him in action can testify, SPJ’s a careful and entertaining communicator of ideas, so that’s no surprise &mdash; if the other chapters are as good as this one, well, it’s a winner of a book.</p>

<p>Here&#8217;s a summary of the interview.  Hopefully it contains enough to tantalise/encourage purchase, but not enough to give away the farm.  :-)  (And remember, this is just one chapter of the book.)</p>

<p>Seibel starts as he seems to start every chapter (modulo small variations), by asking &#8220;When did you learn to program?&#8221;.  SPJ tells us about his school days, and his time as an undergraduate at Cambridge, through into industry and back to academia at UCL, and then on to a Professorship at Glasgow.  Along the way we hear about some of the machines he programmed, and impressive things he did on them &mdash; such as &#8220;a program to extract 24-digit square roots&#8221; on his school&#8217;s computer with 100 8-digit memory locations, entered directly in machine code, because that&#8217;s all it had.  Hearing about heroic stuff like this always makes me feel a bit bad, for having merely human levels of curiousity and drive as a schoolchild, and for a while I was worried the interview would be dominated by this historical stuff, since it went on for a few pages.  Then I realised quite how long the chapter is (35 pages), and felt better.  :-)</p>

<p>One thing I didn&#8217;t know was that SPJ doesn&#8217;t have a PhD.  (Another thing I didn&#8217;t know was that neither does <a href="http://en.wikipedia.org/wiki/Robin_Milner">Robin Milner</a>, apparently.  Wow.)  He discusses how that happened, and why one does a PhD, what its value is, etc., and also some personal philosophy of his approach to research.  As someone who enrolled on a PhD just last week, I found this bit quite inspirational:</p>

<blockquote>

  <p>He [<a href="http://www.cs.ucl.ac.uk/staff/j.washbrook/">John Washbrook</a>] said, &#8220;Just start something, no matter how humble.&#8221;  This is not really about programming, this is about research.  But no matter how humble and unoriginal and unimportant it may seem, start something and wroite a paper about it.  So that&#8217;s what I did.  It turned out to be a very significant piece of advice.</p>

  <p>I&#8217;ve told that to every research student I&#8217;ve ever had since.  Because it&#8217;s how you get started.  Once you start the mill turning then computer science is very fractal &mdash; almost everything turns out to be interesting, because the subject grows ahead of you.  It&#8217;s not like a fixed thing that&#8217;s there that you&#8217;ve got to discover.  It just expands.</p>

</blockquote>

<p>This leads into a few pages about functional programming in general, its popularity in the research community, its practicality, and the ways this research is feeding ideas back into the mainstream.  There&#8217;s a bit of discussion of the vexed question of how to do experiments on programmer productivity/experience: how do you verify, other than anecdotally, that such-and-such a language (or feature) actually benefits the programmer or program?  He mentions some interesting sounding work at Microsoft (&#8221;<a href="http://blogs.msdn.com/stevencl/">Steve Clarke</a> and his colleagues at Redmond&#8221;) on this, at the API level.  Then it&#8217;s back to how SPJ got into FP; he says he was influenced by being taught by <a href="http://www.arthurnorman.org/">Arthur Norman</a> at Cambridge, where seeing a doubly-linked list implemented without side-effects was an &#8216;aha&#8217; moment, and that <a href="http://en.wikipedia.org/wiki/David_Turner_%28computer_scientist%29">David Turner</a>&#8217;s work on <a href="http://en.wikipedia.org/wiki/SKI_combinator_calculus">S-K combinators</a> was also really inspiring and exciting to him &mdash; and says a bit about what that means for FP implementation.</p>

<p>Then laziness comes up: it was another interesting thing which motivated him, and has turned out to be a big idea, not least because it kept the focus on purity, which is the Big Win, he now realises.  He talks about the old embarassing I/O situation, and the <a href="http://research.microsoft.com/en-us/um/people/simonpj/papers/history-of-haskell/">stream-based approach</a> to &#8217;solving&#8217; this, and just mentions monads here before being steered elsewhere by Seibel, never to return&#8230; :-)</p>

<p>He discusses his work on compiler writing (and GHC in particular of course), and the pros and cons of type-checking and static checks, including the problems of generic programming in a statically-typed world.  This leads to a discussion of how he thinks about and designs software (unsurprisingly, its driven by types), and his &#8220;terribly primitive&#8221; programming environment (about the same as mine, except I&#8217;m one of the people he mentions that &#8220;just live their whole lives in ghci&#8221;), and his approaches to debugging.  (Here he mentions some work <a href="http://pepeiborra.blogspot.com/">Pepe Iborra</a> did on debugging for Haskell &mdash; could he mean <a href="http://www.haskell.org/ghc/docs/latest/html/users_guide/ghci-debugger.html">this?</a> Pepe&#8217;s blog mentions <a href="http://pepeiborra.blogspot.com/search/label/ghci_debugger">that</a> in 2006, but SPJ says he did the work &#8220;earlier this year&#8221;.  So has Pepe done something more recent, or did the interview take place in 2006/7?  I suspect the latter?)</p>

<p>On the subject of writing correct software, Seibel asks what he thinks about formal proofs, and his replies are as sensible as you&#8217;d expect &mdash; skeptical about &#8216;big up front&#8217; specification/proof for (now) well-rehearsed reasons, but hopeful about &#8220;partial specifications&#8221; of program properties, e.g. in the style of <a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/">QuickCheck</a>.</p>

<p>Then we get six pages about <a href="http://en.wikipedia.org/wiki/Software_transactional_memory">STM</a>.  :-) Seibel starts by passing on a question from <a href="http://en.wikipedia.org/wiki/Guy_L._Steele,_Jr.">Guy Steele</a>: &#8220;Is STM going to save the world?&#8221;.  The typically sensible answer is of course not: <a href="http://en.wikipedia.org/wiki/No_Silver_Bullet">No Silver Bullet</a>, there are various ways to skin the concurrency cat, but that compared to locks &amp; variables STM is a clear win every time.  He talks about problems of <a href="http://en.wikipedia.org/wiki/Resource_starvation">starvation</a>, and why that&#8217;s particularly problematic with <a href="http://en.wikipedia.org/wiki/Optimistic_concurrency_control">optimistic</a> approaches to concurrency, and comes back to the partial specification idea, discussing how STM lets you think more compositionally in terms of pre- and post-conditions than some other approaches.  The STM discussion ends with him telling how he came to it via a talk by <a href="http://research.microsoft.com/en-us/um/people/tharris/">Tim Harris</a> about STM in Java, and the realisation that STM could be made to fly so much more easily in Haskell than Java &mdash; leaving implementor brainspace free to invent mechanisms such as <tt>orElse</tt> which the Java guys hadn&#8217;t spotted (and example of FP research feeding back into the mainstream).  &#8220;There was less crap, basically, so the cool idea stood out in high relief.&#8221;</p>

<p>Seibel then asks, &#8220;What&#8217;s your desert-island list of books for programmers?&#8221;  I don&#8217;t want to give it away here (buy the book!  It&#8217;s great!), but I&#8217;m sad to say I only own one of the books mentioned.</p>

<p>For the last six pages of the interview, discussion turns to SPJ&#8217;s everyday programming practice (he still loves it), programming as craft vs engineering (a false dichotomy, to SPJ), programming in the large, what it means for code to be beautiful, and code longevity.  SPJ discusses how working in research allows you to put more time and energy into keeping things beautiful, and the tensions in industry that lead to &#8216;big systems full of goop&#8217;, and broad (rather than beautiful) APIs.  It&#8217;s all insightful stuff, and his preferences, likes and dislikes echo my own so strongly that I&#8217;m glad I&#8217;m still working in research too, at least for now.</p>

<p>Overall, as I said, I really enjoyed it.  I learnt a lot about the man, and a few things about programming I didn&#8217;t know (I haven&#8217;t really looked at STM yet, in particular).  Cool.</p>

<p>Oh, and for a nice perspective on the relative longevities of limestone and granite alluded to in the quote I opened this with, check out this 1986 documentary taking a 30-minute tour round the entire British coastline: <a href="http://www.bbc.co.uk/archive/aerialjourneys/5334.shtml">Round Britain Whizz</a>.  :-)</p>

<p>(Also, if you haven&#8217;t seen it yet, <a href="http://www.reddit.com/r/programming/comments/9oqpw/excellent_interview_with_simon_peyton_jones_and/">this is good</a>, too.</p>
]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/10/01/coders-at-work-simon-peyton-jones/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Generating an index of Haskell haddock docs automatically</title>
		<link>http://gimbo.org.uk/blog/2009/09/23/generating-an-index-of-haskell-haddock-docs-automatically/</link>
		<comments>http://gimbo.org.uk/blog/2009/09/23/generating-an-index-of-haskell-haddock-docs-automatically/#comments</comments>
		<pubDate>Wed, 23 Sep 2009 13:55:35 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2516</guid>
		<description><![CDATA[Haskell&#8217;s great, and has a lovely documentation generation system called haddock.  Even better, if you install one of Haskell&#8217;s many third-party libraries using the excellent cabal install, it will (if you configure it to do so) generate these docs for you.  Having local copies of documentation like this is always good for when [...]]]></description>
			<content:encoded><![CDATA[<p>Haskell&#8217;s great, and has a lovely documentation generation system called <a href="http://www.haskell.org/haddock/">haddock</a>.  Even better, if you install one of Haskell&#8217;s many <a href="http://hackage.haskell.org/packages/archive/pkg-list.html">third-party libraries</a> using the excellent <a href="http://www.haskell.org/cabal/">cabal install</a>, it will (if you configure it to do so) generate these docs for you.  Having local copies of documentation like this is always good for when you&#8217;re offline, so this is A Good Thing.</p>

<p>Sadly, there&#8217;s no master index of what&#8217;s installed.  I&#8217;ve got it configured to install globally, so the docs go into <tt>/usr/local/share/doc</tt>, and each (version of each) package gets a folder of its own there; if you&#8217;ve got cabal calling haddock, that folder will contain an <tt>html</tt> folder with the docs in, but it&#8217;s tedious to click through an (otherwise empty) folder to get to it each time, and the whole setup&#8217;s not very pretty or informative (and the lexicographic sorting is case-senstivie, which I don&#8217;t much like).  Eg:</p>

<img src="http://img.skitch.com/20090923-ddbbt2endjdq4aq25iwkseht74.png" alt="Bare index of Haskell docs" title="Bare index of Haskell docs" /img>

<p>People have <a href="http://thread.gmane.org/gmane.comp.lang.haskell.cafe/53531/focus=53572">attacked this problem before</a>, but PHP makes my skin itch, and I can&#8217;t be bothered with apache, so a simpler, static solution seemed right for me.</p>

<p>Thus, I&#8217;ve knocked up a (quick, dirty, nasty) python script to generate the index.  As a happy side-effect, I&#8217;ve pointed it at the hackage CSS file, so it&#8217;s pleasingly pretty and familiar:</p>

<img src="http://img.skitch.com/20090923-tk9txj8wwphhpiys7s9md5g2f5.png" alt="Pretty index of Haskell docs" title="Pretty index of Haskell docs" /img>

<p>I did it in python because that&#8217;s still my go-to &#8220;hack stuff together in a hurry&#8221; language, I guess; but I was <i>very nearly</i> did it in Haskell.  Mainly it was library knowledge that drove me.  Also perhaps I fancied a break.  Hmmm.  Next time, for sure.</p>

<p>If anyone&#8217;s interested in the code (the doc path is hardcoded, so if you&#8217;re installing user docs, change it), you can view it pretty/download it <a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=9737#a9742">via this link</a>, or just check it out here.  Oh, and what about the &#8220;automatically&#8221; part?  Well, just stick it in a cron job&#8230; ;-)</p>

<p><b>Update</b>: I realised I wasn&#8217;t linking to the actual index.html file, which kinda defeated the point of the script!  However, it&#8217;s an easy fix.  The line that says:</p>

<pre><code>
                s.write('&lt;a href="file://%s"&gt;' % package.path)
</code></pre>

<p>should actually say:</p>

<pre><code>
                s.write('&lt;a href="file://%s"&gt;' % os.path.join(package.path, 'html', 'index.html'))
</code></pre>

<p>Aaaanyway&#8230;</p>

<span id="more-2516"></span>

<pre><code>#!/usr/bin/env python

# Horribly hacked-together script to generate an HTML index page for
# Haddock-generated Haskell package docs.  Note that the docs
# directory is hard-coded, below: see the comments there.

import os
import re
import StringIO

# This is the path to the docs.  Any subdirectory which contains an
# 'html/index.html' will get an entry in the index (all the other are
# listed separately at the end).

# The index is written to 'index.html' at this path.

PATH = "/usr/local/share/doc"

class Package:

    def __init__(self, name, path):
        self.name = name
        self.path = path
        self.title = self._seekTitle()

    def __cmp__(self, other):
        return cmp(self.name.lower(), other.name.lower())

    def index(self):
        return os.path.join(self.path, 'html', 'index.html')

    titleRE = r'&gt;.*: (.*)&lt;/TITLE'

    def _seekTitle(self):
        f = open(self.index())
        d = f.read()
        f.close()
        m = re.search(self.titleRE, d)
        if not m:
            raise ValueError, "Can't extract title from %s" % self.index()
        return m.group(1)

class Builder:

    def __init__(self, path):
        self.path = path
        libs = [l for l in os.listdir(self.path)
                if os.path.isdir(os.path.join(path, l))]
        self.has_html = []
        self.no_html = []
        for lib in libs:
            full = os.path.join(path, lib)
            if self.seek_html(full):
                self.has_html.append(Package(lib, full))
            else:
                self.no_html.append((lib, full))
        self.has_html.sort()
        p = os.path.join(path, 'index.html')
        o = open(p, 'w')
        o.write(self.html())
        o.close()

    def html(self):
        s = StringIO.StringIO()
        s.write('&lt;html&gt;\n')
        s.write('&lt;head&gt;\n')
        s.write('&lt;title&gt;Local Haskell package docs (from Haddock)&lt;/title&gt;\n')
        s.write(('&lt;link rel="stylesheet" type="text/css" '
                 'href="http://hackage.haskell.org/packages/hackage.css"/&gt;\n'))
        s.write('&lt;/head&gt;\n')
        s.write('&lt;body&gt;\n')
        s.write('&lt;h2&gt;Local packages with docs&lt;/h2&gt;\n')

        split = self.splitAlpha()
        keys = split.keys()
        keys.sort()

        s.write('&lt;p class="toc"&gt;\n')
        links = ['&lt;a href="#%s"&gt;%s&lt;/a&gt;' % (start, start) for start in keys]
        s.write(' &amp;bull; '.join(links))
        s.write('&lt;/p&gt;\n')
        
        for start in keys:
            packages = split[start]
            s.write('&lt;h3 class="category"&gt;&lt;a name="%s"&gt;%s&lt;/a&gt;&lt;/h3&gt;\n' % (start, start))
            s.write('  &lt;ul class="packages"&gt;\n')
            for package in packages:
                s.write('    &lt;li&gt;')
                s.write('&lt;a href="file://%s"&gt;' % package.path)
                s.write(package.name)
                s.write('&lt;/a&gt;: %s&lt;/li&gt;\n' % package.title)
            s.write('  &lt;/ul&gt;\n')
            
        s.write('&lt;hr /&gt;')
        s.write('&lt;h2&gt;Directories without HTML docs&lt;/h2&gt;\n')
        s.write('&lt;ul&gt;\n')
        for (name, path) in self.no_html:
            s.write('  &lt;li&gt;&lt;a href="file://%s"&gt;%s&lt;/li&gt;\n' % (path, name))
        s.write('&lt;/ul&gt;\n')
        s.write('&lt;/body&gt;\n')
        s.write('&lt;/html&gt;\n')
        h = s.getvalue()
        return h

    def splitAlpha(self):
        al = {}
        for package in self.has_html:
            start = package.name[0].upper()
            try:
                al[start].append(package)
            except KeyError:
                al[start] = [package]
        return al
            
    def seek_html(self, path):
        items = os.listdir(path)
        if 'html' not in items:
            return False
        html = os.path.join(path, 'html')
        if not os.path.isdir(html):
            return False
        return 'index.html' in os.listdir(html)
        
if __name__ == '__main__':
    builder = Builder(PATH)</code></pre>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/09/23/generating-an-index-of-haskell-haddock-docs-automatically/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Really nice git cheatsheet</title>
		<link>http://gimbo.org.uk/blog/2009/09/17/really-nice-git-cheatsheet/</link>
		<comments>http://gimbo.org.uk/blog/2009/09/17/really-nice-git-cheatsheet/#comments</comments>
		<pubDate>Thu, 17 Sep 2009 13:29:21 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2514</guid>
		<description><![CDATA[Here&#8217;s a nice git cheatsheet, with examples: Everyday GIT With 20 Commands Or So [via brunns].  Really good &#8212; and to think that I didn&#8217;t know about git fsck and git gc!]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a nice git cheatsheet, with examples: <a href="http://www.kernel.org/pub/software/scm/git/docs/everyday.html">Everyday GIT With 20 Commands Or So</a> [via <a href="http://delicious.com/brunns#2009-09-16">brunns</a>].  Really good &mdash; and to think that I didn&#8217;t know about <tt>git fsck</tt> and <tt>git gc</tt>!</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/09/17/really-nice-git-cheatsheet/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>A Haskell shell for computing musical scales, in 58 lines of code.</title>
		<link>http://gimbo.org.uk/blog/2009/09/15/a-haskell-shell-for-computing-musical-scales-in-58-lines-of-code/</link>
		<comments>http://gimbo.org.uk/blog/2009/09/15/a-haskell-shell-for-computing-musical-scales-in-58-lines-of-code/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 20:04:34 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[functional-programming]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2498</guid>
		<description><![CDATA[On my way home from work I had an idea for something I thought I&#8217;d find handy.  Two hours later, I&#8217;ve written it &#8212; in Haskell of course.  :-)

Context: I occasionally make what might kindly be called music, using computers and the like, and I don&#8217;t have any formal musical training.  Consequently, [...]]]></description>
			<content:encoded><![CDATA[<p>On my way home from work I had an idea for something I thought I&#8217;d find handy.  Two hours later, I&#8217;ve written it &mdash; in Haskell of course.  :-)</p>

<p>Context: I occasionally make what might kindly be called music, using computers and the like, and I don&#8217;t have any formal musical training.  Consequently, I sometimes run into trouble regarding keys and scales.  The idea I had was for something which would tell me, given a set of notes (ie the ones I&#8217;ve already used in a piece), what scales those notes are in &mdash; and consequently what <i>other</i> notes might also fit well with them.  Long ago when I used <i>Bars &#038; Pipes</i> on the Amiga, it had a tool for doing this.  I could <a href="http://dmwdev.com/scalefinder.html">buy one for my Mac</a> for about 8UKP (I may yet &mdash; it has a pretty GUI, which I might not be bothered to do), but it seemed I should be able to knock something up.  The data types aren&#8217;t exactly complicated.</p>

<p>So I did it.  I&#8217;ll put the code at the end of this post, <a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=9408">or you can easily download it from here</a>, in 133 lines of literate Haskell (58 lines of actual code).  Here&#8217;s a screenshot showing typical use:</p>

<p><a href="http://skitch.com/gimboland/b9mxn/scale-finder-in-use"><img alt="Haskell scale finder screenshot" title="Haskell scale finder screenshot" src="http://img.skitch.com/20090916-tpy5cqjj2457pyg4rpqutm8fc.png" /></a></p>

<p>Once again, I&#8217;ve been super impressed by how easy Haskell made this &mdash; and I&#8217;m particularly loving the <a href="http://hackage.haskell.org/package/Shellac">Shellac</a> library which gives me an interactive shell with <b>history</b> and graceful recovery from errors &mdash; <b>all in 4 lines of code</b>!</p>

<pre>
<code>&gt; react = mapM_ (uncurry printScale) . checkFit . parseNotes
&gt;     where printScale :: String -&gt; [Note] -&gt; Sh () ()
&gt;           printScale n ns = shellPutStrLn (n ++ ": " ++ ppNotes ns)
&gt; main = runShell (mkShellDescription [] react) haskelineBackend ()</code>
</pre>

<p>OK, I&#8217;m not using any of its juicier features like completion, state, automatic help, etc., but even so, it&#8217;s a great little library.</p>

<p>I could wrap it in a GUI, but to be honest, this&#8217;ll probably do the trick for me, assuming I haven&#8217;t made any big screw-ups, or got the scale definitions wrong.  If anyone&#8217;s looking for a minimal Shellac example, maybe it&#8217;ll be useful.</p>

<p>(<b>Update</b> 2009-09-16 13:37: To get this up and running, if you&#8217;re not already a Haskeller, the following should suffice: 1. Download and install <a href="http://hackage.haskell.org/platform/">The Haskell Platform</a> &ndash; nice &#8216;n&#8217; easy.  2. Open a shell and issue <tt>cabal install Shellac-haskeline</tt> or possibly <tt>sudo cabal install --global Shellac-haskeline</tt>.  3. Download the code (from hpaste.org) and (still in a shell) issue <tt>ghci Scales</tt>, and when that&#8217;s loaded issue <tt>main</tt>.  Or if you want to compile an executable, try <tt>ghc --make -main-is Scale.lhs Scale.lhs</tt>, just like in the screenshot.  That should do it &mdash; I&#8217;d love to know if I&#8217;ve missed anything and/or if that works!)</p>

<p>Here&#8217;s the code (but, again, it&#8217;s <a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=9408">prettier and easier to download from hpaste</a>):</p>

<span id="more-2498"></span>

<pre><code>&gt; module Scale where

&gt; import Data.List

I'm going to use Shellac for interactivity...

&gt; import System.Console.Shell
&gt; import System.Console.Shell.Backend.Haskeline
&gt; import System.Console.Shell.ShellMonad

... HughesPJ for pretty printing (in a small way, but it's just so pretty)...

&gt; import Text.PrettyPrint.HughesPJ

... and Text.Regex for splitting a string on spaces.

&gt; import Text.Regex

So the idea is to compute the possible scales a given set of notes
might be part of.

Scales can be represented simply as lists of intervals, naturally
denoting the tonic as the value 0.

&gt; type Interval = Int
&gt; data Scale = Scale {
&gt;       scaleName :: String,
&gt;       scaleIntervals :: [Interval]
&gt;       } deriving Show

We know a few different scales, namely the ones whose Wikipedia
articles made a reasonable amount of sense to us... :-) This may be
stupid and/or wrong, and there are certainly nicer ways to represent
these scales, but it'll do for now.

&gt; knownScales :: [Scale]
&gt; knownScales = [Scale "Major" [0, 2, 4, 5, 7, 9, 11]
&gt;               ,Scale "Minor"            [0, 2, 3, 5, 7, 8, 10]
&gt;               ,Scale "Harmonic Minor"   [0, 2, 3, 5, 7, 8, 11]
&gt;               ,Scale "Major Pentatonic"          [0, 2, 4, 7, 9]
&gt;               ,Scale "Relative Minor Pentatonic" [0, 3, 5, 7, 10]
&gt;               ,Scale "Yo" [0, 2, 5, 7, 9]
&gt;               ]

Notes (A, B, C, etc.) can also be represented as integers.

&gt; type Note = Int

Then we can use modular arithmetic (Z12) without any hassles.

&gt; noteMod :: Note -&gt; Note
&gt; noteMod n = n `mod` 12

Given a base note and a scale, we can compute the notes in that scale.

&gt; scaleNotes :: Note -&gt; Scale -&gt; [Note]
&gt; scaleNotes base (Scale _ scale) =
&gt;     nub . sort . map noteMod $ zipWith (+) (repeat base) scale

We will also want to refer to notes by their names.

&gt; type NoteName = String

And so we need to know the order those names come in.  We'll
arbitrarily set C to 0.

&gt; chromatic :: [NoteName]
&gt; chromatic = ["C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A",
&gt;              "A#", "B"]

We need to be able to convert between note names and numbers easily.
We just die if anything goes wrong (i.e. unknown note name).

&gt; namedNote :: NoteName -&gt; Note
&gt; namedNote name = case elemIndex name chromatic of
&gt;                  Just a -&gt; a
&gt;                  Nothing -&gt; error $ "unknown note " ++ name

&gt; noteName :: Note -&gt; NoteName
&gt; noteName note = chromatic !! noteMod note

Given a set of base notes and a set of scales, we can compute all
possible combinations, for each one returning its name (e.g. "C
Major") and the notes found in it.

&gt; mkScales :: [Note] -&gt; [Scale] -&gt; [(String, [Note])]
&gt; mkScales notes scales =
&gt;     do note &lt;- notes
&gt;        scale &lt;- scales
&gt;        return (noteName note ++ " " ++ scaleName scale,
&gt;                scaleNotes note scale)

Then we can compute all the scales we know about.

&gt; allScales :: [(String, [Note])]
&gt; allScales = mkScales [0..11] knownScales

For I/O we want to be able to parse strings of space-separated note
names into lists of note numbers.

&gt; parseNotes :: String -&gt; [Note]
&gt; parseNotes = map namedNote . splitRegex (mkRegex " +")

... and we want to be able to pretty print the same.

&gt; ppNotes :: [Note] -&gt; String
&gt; ppNotes = show . hsep . map (text . noteName) . nub . sort . map noteMod

Then, to compute the scales a given set of notes belong to, we can
just stupidly brute force iterate over every note in the octave, and
every scale we know, and just decide if the set of notes we've got
fits or not.

&gt; checkFit :: [Note] -&gt; [(String, [Note])]
&gt; checkFit notes = filter ((notes `isSubList`) . snd) allScales
&gt;     where isSubList :: (Eq a) =&gt; [a] -&gt; [a] -&gt; Bool
&gt;           isSubList x y = null $ x \\ y

OK, let's do some interactivity, courtesy of Shellac.

We interpret whatever the user enteres as a space-separated list of
note names, and in response we print the names (and notes) of every
scale those notes are in.

&gt; react :: String -&gt; Sh () ()
&gt; react = mapM_ (uncurry printScale) . checkFit . parseNotes
&gt;     where printScale :: String -&gt; [Note] -&gt; Sh () ()
&gt;           printScale n ns = shellPutStrLn (n ++ ": " ++ ppNotes ns)

Our main function just runs that function in an interactive shell.

&gt; main :: IO ()
&gt; main = runShell (mkShellDescription [] react) haskelineBackend ()</code></pre>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/09/15/a-haskell-shell-for-computing-musical-scales-in-58-lines-of-code/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>On the money</title>
		<link>http://gimbo.org.uk/blog/2009/09/15/on-the-money/</link>
		<comments>http://gimbo.org.uk/blog/2009/09/15/on-the-money/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 10:23:49 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[cartoon]]></category>
		<category><![CDATA[gimbo]]></category>
		<category><![CDATA[humour]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2495</guid>
		<description><![CDATA[My life. :-)]]></description>
			<content:encoded><![CDATA[<p><a href="http://wondermark.com/552/">My life</a>. :-)</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/09/15/on-the-money/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>An official apology to Alan Turing</title>
		<link>http://gimbo.org.uk/blog/2009/09/11/an-official-apology-to-alan-turing/</link>
		<comments>http://gimbo.org.uk/blog/2009/09/11/an-official-apology-to-alan-turing/#comments</comments>
		<pubDate>Fri, 11 Sep 2009 11:22:49 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[computer-science]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[sexuality]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2493</guid>
		<description><![CDATA[An official apology to Alan Turing. Win.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.number10.gov.uk/Page20571">An official apology to Alan Turing</a>. Win.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/09/11/an-official-apology-to-alan-turing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Why is there peace?</title>
		<link>http://gimbo.org.uk/blog/2009/08/10/why-is-there-peace/</link>
		<comments>http://gimbo.org.uk/blog/2009/08/10/why-is-there-peace/#comments</comments>
		<pubDate>Mon, 10 Aug 2009 16:04:26 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[earth]]></category>
		<category><![CDATA[economics]]></category>
		<category><![CDATA[history]]></category>
		<category><![CDATA[people]]></category>
		<category><![CDATA[philosophy]]></category>
		<category><![CDATA[politics]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2491</guid>
		<description><![CDATA[Why is There Peace? &#8212; violence is declining, over history, at least in relative terms, though not, one suspects, absolute ones.]]></description>
			<content:encoded><![CDATA[<p><a href="http://greatergood.berkeley.edu/greatergood/2009april/Pinker054.php">Why is There Peace?</a> &mdash; violence is declining, over history, at least in relative terms, though not, one suspects, absolute ones.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/08/10/why-is-there-peace/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>A &#8220;Monte Hall&#8221; problem solved in Haskell</title>
		<link>http://gimbo.org.uk/blog/2009/07/25/a-monte-hall-problem-solved-in-haskell/</link>
		<comments>http://gimbo.org.uk/blog/2009/07/25/a-monte-hall-problem-solved-in-haskell/#comments</comments>
		<pubDate>Sat, 25 Jul 2009 00:00:16 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[functional-programming]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2486</guid>
		<description><![CDATA[I&#8217;ve just written a solution to today&#8217;s Programming Praxis puzzle, which requires you, essentially, to write a Monte Carlo attack on the Monty Hall problem.  Thus, the awful pun in this post&#8217;s title, in case you missed it.  ;-)

Here&#8217;s my solution.

It was a lot of fun.  I started out feeling like I [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve just written a solution to <a href="http://programmingpraxis.com/2009/07/24/lets-make-a-deal">today&#8217;s Programming Praxis puzzle</a>, which requires you, essentially, to write a <a href="http://en.wikipedia.org/wiki/Monte_Carlo_method">Monte Carlo</a> attack on the <a href="http://en.wikipedia.org/wiki/Monty_Hall_problem">Monty Hall problem</a>.  Thus, the awful pun in this post&#8217;s title, in case you missed it.  ;-)</p>

<p><a href="http://hpaste.org/fastcgi/hpaste.fcgi/view?id=7478">Here&#8217;s my solution</a>.</p>

<p>It was a lot of fun.  I started out feeling like I should be able to do it, but not quite knowing what direction to take, so first of all I was writing some data types for things like <tt>Door = Car | Goat</tt>, etc. but pretty quickly realised it was just a matter of door numbers.  My first working solution was actually a bit longer, because of some intermediate steps (for example the first thing I figured out, in its own function, was how to compute which goat door would get shown to the player given a (car, choice) pair).  Then <a href="http://community.haskell.org/~ndm/hlint/">hlint</a> gave me a couple of hints, like using replicateM, and I compacted it down to what we see here.  I&#8217;m sure it has naive aspects, but I&#8217;m pretty happy with it &mdash; and I&#8217;m loving doing the Praxis problems.</p>
]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/07/25/a-monte-hall-problem-solved-in-haskell/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>DIY magnetic spice rack</title>
		<link>http://gimbo.org.uk/blog/2009/05/30/diy-magnetic-spice-rack/</link>
		<comments>http://gimbo.org.uk/blog/2009/05/30/diy-magnetic-spice-rack/#comments</comments>
		<pubDate>Sat, 30 May 2009 20:26:07 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[food]]></category>
		<category><![CDATA[gadget]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2484</guid>
		<description><![CDATA[I love this idea [via lifehacker].]]></description>
			<content:encoded><![CDATA[<p><a href="http://myaimistrue.com/2007/01/diy-magnetic-spice-rack/" class="broken_link" >I love this idea</a> [via <a href="http://lifehacker.com/5273001/top-10-magnet-hacks">lifehacker</a>].]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/05/30/diy-magnetic-spice-rack/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Shake a shake a shake a tail feather</title>
		<link>http://gimbo.org.uk/blog/2009/05/12/shake-a-shake-a-shake-a-tail-feather/</link>
		<comments>http://gimbo.org.uk/blog/2009/05/12/shake-a-shake-a-shake-a-tail-feather/#comments</comments>
		<pubDate>Tue, 12 May 2009 11:48:34 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[beauty]]></category>
		<category><![CDATA[dance]]></category>
		<category><![CDATA[humour]]></category>
		<category><![CDATA[music]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2480</guid>
		<description><![CDATA[You haven&#8217;t experienced true joy until you&#8217;ve watched this cockatoo dancing to Ray Charles [via nicolas].]]></description>
			<content:encoded><![CDATA[<p>You haven&#8217;t experienced true joy until you&#8217;ve watched this <a href="http://www.maniacworld.com/bird-loves-ray-charles.html">cockatoo dancing to Ray Charles</a> [via <a href="https://twitter.com/camaelon/statuses/1768508345">nicolas</a>].</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/05/12/shake-a-shake-a-shake-a-tail-feather/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Alan Dix on &#8220;Language and Action: sequential associative parsing&#8221;</title>
		<link>http://gimbo.org.uk/blog/2009/05/10/alan-dix-on-language-and-action-sequential-associative-parsing/</link>
		<comments>http://gimbo.org.uk/blog/2009/05/10/alan-dix-on-language-and-action-sequential-associative-parsing/#comments</comments>
		<pubDate>Sun, 10 May 2009 13:20:07 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[computer-science]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[hci]]></category>
		<category><![CDATA[languages]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2478</guid>
		<description><![CDATA[Alan Dix on the difference between how humans parse language, and how machines do so &#8212; and associated impacts on interaction. Interesting stuff, as ever.]]></description>
			<content:encoded><![CDATA[<p>Alan Dix on <a href="http://www.alandix.com/blog/2009/05/09/language-and-action-sequential-associative-parsing/">the difference between how humans parse language, and how machines do so</a> &mdash; and associated impacts on interaction. Interesting stuff, as ever.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/05/10/alan-dix-on-language-and-action-sequential-associative-parsing/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Eastside Roots</title>
		<link>http://gimbo.org.uk/blog/2009/04/29/eastside-roots/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/29/eastside-roots/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 09:37:16 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[diary]]></category>
		<category><![CDATA[earth]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2475</guid>
		<description><![CDATA[Heading to Cornwall on a train last Friday, I spotted something interesting as we neared Bristol Temple Meads: Eastside Roots, a community gardening project &#8212; look out for it by Stapleton Road station.]]></description>
			<content:encoded><![CDATA[<p>Heading to Cornwall on a train last Friday, I spotted something interesting as we neared Bristol Temple Meads: <a href="http://www.eastsideroots.org.uk/">Eastside Roots</a>, a community gardening project &mdash; look out for it by Stapleton Road <a href="http://en.wikipedia.org/wiki/Stapleton_Road_railway_station">station</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/29/eastside-roots/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>I once told her&#8230;</title>
		<link>http://gimbo.org.uk/blog/2009/04/28/i-once-told-her/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/28/i-once-told-her/#comments</comments>
		<pubDate>Tue, 28 Apr 2009 15:40:43 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[art]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[diary]]></category>
		<category><![CDATA[gimbo]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2472</guid>
		<description><![CDATA[I am that man.

(Shame the sound quality on the video&#8217;s so poor though.)]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.someoneoncetoldme.com/gallery/27042009">I am that man</a>.</p>

<p>(Shame the sound quality on the video&#8217;s so poor though.)</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/28/i-once-told-her/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>&#8220;Believe Me, It&#8217;s Torture&#8221;</title>
		<link>http://gimbo.org.uk/blog/2009/04/24/believe-me-its-torture/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/24/believe-me-its-torture/#comments</comments>
		<pubDate>Fri, 24 Apr 2009 08:26:42 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[earth]]></category>
		<category><![CDATA[economics]]></category>
		<category><![CDATA[environment]]></category>
		<category><![CDATA[people]]></category>
		<category><![CDATA[politics]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2469</guid>
		<description><![CDATA[Christopher Hitchens gets waterboarded [via Dawkins].]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.vanityfair.com/politics/features/2008/08/hitchens200808">Christopher Hitchens gets waterboarded</a> [via <a href="http://richarddawkins.net/article,3775,Believe-Me-Its-Torture,Christopher-Hitchens">Dawkins</a>].</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/24/believe-me-its-torture/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The evolution of the eye</title>
		<link>http://gimbo.org.uk/blog/2009/04/22/the-evolution-of-the-eye/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/22/the-evolution-of-the-eye/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 20:37:32 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[earth]]></category>
		<category><![CDATA[politics]]></category>
		<category><![CDATA[religion]]></category>
		<category><![CDATA[science]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2467</guid>
		<description><![CDATA[Anti-evolutionists sometimes use the human eye as an argument for a creator; here&#8217;s David Attenborough explaining why that&#8217;s tosh [via frosty]. ]]></description>
			<content:encoded><![CDATA[<p>Anti-evolutionists sometimes use the human eye as an argument for a creator; <a href="http://www.youtube.com/watch?v=Yj_lNQerUJ4">here&#8217;s David Attenborough explaining why that&#8217;s tosh</a> [via <a href="http://frosty.tumblr.com/post/99014904/sir-david-attenborough-describes-the-evolution-of">frosty</a>].</p> ]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/22/the-evolution-of-the-eye/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>If Philosophers Were Programmers</title>
		<link>http://gimbo.org.uk/blog/2009/04/21/if-philosophers-were-programmers/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/21/if-philosophers-were-programmers/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 23:19:28 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[computer-science]]></category>
		<category><![CDATA[computing]]></category>
		<category><![CDATA[humour]]></category>
		<category><![CDATA[philosophy]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2464</guid>
		<description><![CDATA[If Philosophers Were Programmers [brunns].

Nice to see that Wittgenstein (or at least, one of the Wittgensteins) is also a Haskell man&#8230;]]></description>
			<content:encoded><![CDATA[<p><a href="http://developeronline.blogspot.com/2009/04/if-philosophers-were-programmers.html">If Philosophers Were Programmers</a> [<a href="http://delicious.com/brunns#2009-04-20">brunns</a>].</p>

<p>Nice to see that Wittgenstein (or at least, one of the Wittgensteins) is also a Haskell man&#8230;</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/21/if-philosophers-were-programmers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Cassini&#8217;s continued mission</title>
		<link>http://gimbo.org.uk/blog/2009/04/21/cassinis-continued-mission/</link>
		<comments>http://gimbo.org.uk/blog/2009/04/21/cassinis-continued-mission/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 15:04:46 +0000</pubDate>
		<dc:creator>gimbo</dc:creator>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[art]]></category>
		<category><![CDATA[beauty]]></category>
		<category><![CDATA[photo]]></category>
		<category><![CDATA[science]]></category>

		<guid isPermaLink="false">http://gimbo.org.uk/blog/?p=2462</guid>
		<description><![CDATA[Some truly incredible pictures of Saturn and its friends.]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.boston.com/bigpicture/2009/04/cassinis_continued_mission.html">Some truly incredible pictures of Saturn and its friends</a>.</p>]]></content:encoded>
			<wfw:commentRss>http://gimbo.org.uk/blog/2009/04/21/cassinis-continued-mission/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
