<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss 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/" version="2.0">

<channel>
	<title>Tapdancing Goats</title>
	
	<link>http://www.tapdancinggoats.com</link>
	<description>A parfait of physics, Linux, LaTeX, and coding tips large and small.</description>
	<lastBuildDate>Wed, 25 Jan 2012 03:14:39 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/Tapdancinggoats" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="tapdancinggoats" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><item>
		<title>LaTeX Coffee Stains</title>
		<link>http://www.tapdancinggoats.com/latex-coffee-stains.htm</link>
		<comments>http://www.tapdancinggoats.com/latex-coffee-stains.htm#comments</comments>
		<pubDate>Wed, 25 Jan 2012 03:14:39 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[LaTeX]]></category>
		<category><![CDATA[Links]]></category>
		<category><![CDATA[coffee]]></category>
		<category><![CDATA[silly]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=758</guid>
		<description><![CDATA[LaTeX Coffee Stains is a new LaTeX style by Hanno Rein that will add coffee stains to LaTeX documents, in case you&#8217;re too hip to do it the old fashioned way.]]></description>
			<content:encoded><![CDATA[<p><a href="http://hanno-rein.de/archives/349">LaTeX Coffee Stains</a> is a new LaTeX style by Hanno Rein that will add coffee stains to LaTeX documents, in case you&#8217;re too hip to do it the old fashioned way.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=aJcszqA7fJE:ej6NXk-MHDA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=aJcszqA7fJE:ej6NXk-MHDA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=aJcszqA7fJE:ej6NXk-MHDA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=aJcszqA7fJE:ej6NXk-MHDA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=aJcszqA7fJE:ej6NXk-MHDA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=aJcszqA7fJE:ej6NXk-MHDA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=aJcszqA7fJE:ej6NXk-MHDA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=aJcszqA7fJE:ej6NXk-MHDA:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/aJcszqA7fJE" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/latex-coffee-stains.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Remember the Reason for the Season</title>
		<link>http://www.tapdancinggoats.com/remember-the-reason-for-the-season.htm</link>
		<comments>http://www.tapdancinggoats.com/remember-the-reason-for-the-season.htm#comments</comments>
		<pubDate>Fri, 23 Dec 2011 10:01:33 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Humor]]></category>
		<category><![CDATA[axial tilt]]></category>
		<category><![CDATA[christmas]]></category>
		<category><![CDATA[earth]]></category>
		<category><![CDATA[holidays]]></category>
		<category><![CDATA[pun]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=746</guid>
		<description />
			<content:encoded><![CDATA[<p><a href="http://www.tapdancinggoats.com/wp-content/uploads/2011/12/season.jpg"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2011/12/season.jpg" alt="" title="Remember the Reason for the Season" width="572" height="607" class="aligncenter size-full wp-image-752" /></a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=7bRORYUqbtA:tYHSvPWR4fg:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=7bRORYUqbtA:tYHSvPWR4fg:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=7bRORYUqbtA:tYHSvPWR4fg:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=7bRORYUqbtA:tYHSvPWR4fg:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=7bRORYUqbtA:tYHSvPWR4fg:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=7bRORYUqbtA:tYHSvPWR4fg:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=7bRORYUqbtA:tYHSvPWR4fg:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=7bRORYUqbtA:tYHSvPWR4fg:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/7bRORYUqbtA" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/remember-the-reason-for-the-season.htm/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Puzzle 1</title>
		<link>http://www.tapdancinggoats.com/puzzle-1.htm</link>
		<comments>http://www.tapdancinggoats.com/puzzle-1.htm#comments</comments>
		<pubDate>Sat, 22 Oct 2011 08:13:12 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Puzzles]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=740</guid>
		<description><![CDATA[Rules and hints: The solution is one word. Post a comment with your answer. I will moderate comments so incorrect solutions will not appear. Feel free to put a link to your profile or contact information in the comment with your solution, so people that are impressed with your puzzle skillz can find you. Don&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>Rules and hints:</p>

<ul>
<li>The solution is one word.</li>
<li>Post a comment with your answer.  I will moderate comments so incorrect solutions will not appear.</li>
<li>Feel free to put a link to your profile or contact information in the comment with your solution, so people that are impressed with your puzzle skillz can find you.</li>
<li>Don&#8217;t submit more than one solution per day or you will be disqualified.</li>
<li>If I get more than one solution within a few days, I will post them all.</li>
<li>After a solution is posted, comments will be closed.</li>
</ul>

<p><a href="http://www.tapdancinggoats.com/wp-content/uploads/2011/10/puzzle1.png"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2011/10/puzzle1.png" alt="" title="puzzle1" width="320" height="512" class="aligncenter size-full wp-image-741" /></a></p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ZkBLCPKu678:YaQMZl1C4kU:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ZkBLCPKu678:YaQMZl1C4kU:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ZkBLCPKu678:YaQMZl1C4kU:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ZkBLCPKu678:YaQMZl1C4kU:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ZkBLCPKu678:YaQMZl1C4kU:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ZkBLCPKu678:YaQMZl1C4kU:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=ZkBLCPKu678:YaQMZl1C4kU:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=ZkBLCPKu678:YaQMZl1C4kU:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/ZkBLCPKu678" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/puzzle-1.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>So You Occupied Wall Street?  Now What?</title>
		<link>http://www.tapdancinggoats.com/so-you-occupied-wall-street-now-what.htm</link>
		<comments>http://www.tapdancinggoats.com/so-you-occupied-wall-street-now-what.htm#comments</comments>
		<pubDate>Sat, 01 Oct 2011 21:37:07 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Politics]]></category>
		<category><![CDATA[civil resistance]]></category>
		<category><![CDATA[occupy wall street]]></category>
		<category><![CDATA[protest]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=731</guid>
		<description><![CDATA[Wall Street is occupied! Okay. Now what? As far as I can tell, this protest crystallized around anger directed at the people who got away with stealing billions from the rest of us. Lamenting the past is not the organizing principle for a political movement. This is a candlelight vigil for our economy. What do [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Wall Street is occupied!</strong></p>

<p>Okay.  Now what?</p>

<p>As far as I can tell, this protest crystallized around anger directed at the people who got away with stealing billions from the rest of us.  Lamenting the past is not the organizing principle for a political movement.  This is a candlelight vigil for our economy.</p>

<h3>What do we want?</h3>

<p>If you think that getting mad as hell is all it takes to effect change, you need to go back and finish watching Network.  Anger isn&#8217;t enough.  We saw the same thing during <a href="http://www.guardian.co.uk/media/2010/dec/08/mastercard-hackers-wikileaks-revenge">the Mastercard hack in Dec. 2010</a>.  What did that achieve?  Nothing.  They had no demands and weren&#8217;t asking the public to help.  If you don&#8217;t have a clear goal you&#8217;re not a protester, you&#8217;re a vandal.  A protest that can effect change needs to have a stated, achievable goal, and a clear call to action.</p>

<p>A clear goal gives a protest a finish line, and it makes the opposition responsible for the costs.  The message of a protest shouldn&#8217;t be, &#8220;We&#8217;re going to destroy your business,&#8221; but rather, &#8220;You can stop this by making a simple change.&#8221;  A protest without a goal is just a public party, and the opposition has no choice but to wait it out.</p>

<h3>At least they&#8217;re doing something?</h3>

<p>Sure, maybe it&#8217;s not well organized, but at least they&#8217;re not just sitting on their butts doing nothing, right?  Really?  That&#8217;s the rock the vote argument, that every eligible person should vote regardless of how well they understand the issues.  Just be heard; it doesn&#8217;t matter what you say.</p>

<p>This protest is going to be completely ineffective.  This isn&#8217;t elementary school, there are no points for participation.  This is going to demoralize people that might have participated in an effective civil action in the future.  Worthless protests are a pressure release valve to prevent effective civil disobedience.</p>

<p>Don&#8217;t just do anything.  Save your energy until you have a clear goal, and a real action that will put pressure on your opposition.  Without those things you aren&#8217;t holding a protest.  You&#8217;re just throwing a party.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xr7eUv4Fi-U:9eh-H6JXPqA:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xr7eUv4Fi-U:9eh-H6JXPqA:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xr7eUv4Fi-U:9eh-H6JXPqA:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xr7eUv4Fi-U:9eh-H6JXPqA:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xr7eUv4Fi-U:9eh-H6JXPqA:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xr7eUv4Fi-U:9eh-H6JXPqA:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=xr7eUv4Fi-U:9eh-H6JXPqA:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=xr7eUv4Fi-U:9eh-H6JXPqA:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/xr7eUv4Fi-U" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/so-you-occupied-wall-street-now-what.htm/feed</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Graham Scan in Haskell</title>
		<link>http://www.tapdancinggoats.com/graham-scan-in-haskell.htm</link>
		<comments>http://www.tapdancinggoats.com/graham-scan-in-haskell.htm#comments</comments>
		<pubDate>Wed, 07 Sep 2011 03:57:04 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Software Development]]></category>
		<category><![CDATA[algorithm]]></category>
		<category><![CDATA[convex hull]]></category>
		<category><![CDATA[Graham scan]]></category>
		<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=719</guid>
		<description><![CDATA[This article follows how I developed an implementation of the Graham scan algorithm in Haskell, missteps and all. I think it&#8217;s valuable to see the process that others use, especially in a &#8220;weird&#8221; language like Haskell. At times, it can seem like most of what you&#8217;ve learned about developing software doesn&#8217;t apply to Haskell, but [...]]]></description>
			<content:encoded><![CDATA[<p>This article follows how I developed an implementation of the <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham scan</a> algorithm in Haskell,
missteps and all.  I think it&#8217;s valuable to see the process that others use, especially in a &#8220;weird&#8221; language like Haskell.  At times, it can seem like most of what you&#8217;ve learned about developing software doesn&#8217;t apply to Haskell, but I think that&#8217;s just because the language allows so much of the scaffolding to be cut away once the software is finished.  Reading Haskell code written by the masters can feel like looking at the Sistine chapel and wondering where they got such long paint brushes.  This will be a step-by-step implementation as I developed it.  I&#8217;m still learning too, so don&#8217;t take this as an example of excellent Haskell style.</p>

<p><span id="more-719"></span></p>

<p>The <a href="http://en.wikipedia.org/wiki/Graham_scan">Graham scan</a> algorithm finds the convex hull of a set of planar points in three
steps.  First, we find the lower-left point in the set (call it <strong>P</strong>).  Second, we
sort the set based on the angle each point makes with <strong>P</strong> and the
x-axis.  Third, we go through the sorted list and keep each point
which makes a &#8220;left turn.&#8221;</p>

<h3>Data Types</h3>

<p>Even before we start, there are some obvious types we need.  We&#8217;ll
need a type to store points.  This could just be a tuple, but I think
the code will be easier to understand if the point type has
accessors.  I&#8217;ll define <code>Point</code> as</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="kw1">data</span> Point a = Point <span class="br0">&#123;</span>px :: a, py :: a<span class="br0">&#125;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;<span class="kw1">deriving</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Show"><span class="kw4">Show</span></a><br />
&nbsp;</div>

<p>I parameterized the number type, so our algorithm can be as general as
possible.  I think we&#8217;ll want a type to represent the result of the
turn calculation too, so define a turn data type:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="kw1">data</span> Turn = Left | Right | Colinear<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">deriving</span> <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Show"><span class="kw4">Show</span></a>, <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Eq"><span class="kw4">Eq</span></a><span class="br0">&#41;</span><br />
&nbsp;</div>

<p>Since I&#8217;m redefining <code>Left</code> and <code>Right</code> here, I have to hide <code>Either</code>
with <code>import Prelude hiding (Either(..))</code>.</p>

<h3>Stubs</h3>

<p>I want to start capturing what I know about the Graham scan function
in code.  First, it will take a set of points and return the points of
the convex hull, so</p>

<div class="dean_ch" style="white-space: wrap;"><br />
grahamScan :: <span class="br0">&#91;</span>Point a<span class="br0">&#93;</span> -&gt; <span class="br0">&#91;</span>Point a<span class="br0">&#93;</span><br />
&nbsp;</div>

<p>Next, the algorithm doesn&#8217;t work right if there are fewer than three
points, so it will generate an error in that case.  There are many ways to handle errors in Haskell.  Some common
methods include putting the function in the Error monad, returning an
Either or Maybe, or returning an empty list.  I&#8217;ll explore other methods in future articles, but since this function is
for experimentation I&#8217;m going to just raise an error.  I&#8217;m not even
going to bother with a detailed error report, so the function will start
like this.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
grahamScan points<br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:length"><span class="kw3">length</span></a> points &lt; <span class="nu0">3</span> = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:error"><span class="kw3">error</span></a> <span class="st0">&quot;Degenerate&quot;</span><br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:otherwise"><span class="kw3">otherwise</span></a> &nbsp; &nbsp; &nbsp; &nbsp; = &#8230;<br />
&nbsp;</div>

<p>Now that I know we have valid input, I can get to the meat of the
algorithm.  First we find the lower left point and sort the point list
with it.  I&#8217;m not sure how to find the lower left point, so I&#8217;ll just defer that to a function called <code>findFirstPoint</code>.  I&#8217;ll use the functions <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:compare"><code>compare</code></a> and <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Function.html#v:on"><code>on</code></a> with a new function <code>angle</code> to create a function that will compare points by their angle.  This new comparator is handed to <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-List.html#v:sortBy"><code>sortBy</code></a> to sort the list.  For now, I set <code>findFirstPoint</code> and <code>angle</code> to <code>undefined</code> so
the code will compile.  Compile early and often; it helps to keep
mistakes from compounding and mutating.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="kw1">let</span> <span class="br0">&#40;</span>firstPoint:rest<span class="br0">&#41;</span> = findFirstPoint points<br />
&nbsp; &nbsp; sortedRest = sortBy <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:compare"><span class="kw3">compare</span></a> `on` <span class="br0">&#40;</span>angle firstPoint<span class="br0">&#41;</span><span class="br0">&#41;</span> rest<br />
&nbsp;</div>

<p>The third step in the algorithm is a bit tricky.  We need to look at
the next three points in the set and decide whether or not to keep the
second point, and the last two points have to be tested along with the first point.
Since our input list is not circular, there has to be special handling
for the end of the list.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
loop <span class="br0">&#40;</span>a:b:<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span> = <span class="kw1">case</span> turn a b firstPoint <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Left -&gt; b : <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp;-&gt; <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
loop <span class="br0">&#40;</span>a:b:c:ps<span class="br0">&#41;</span> = <span class="kw1">case</span> turn a b c <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Left -&gt; b : loop <span class="br0">&#40;</span>b:c:ps<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp;-&gt; loop <span class="br0">&#40;</span>a:c:ps<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>Isn&#8217;t that lovely?  Haskell is so expressive, the code basically reads
like the English description: &#8220;Take the next three points in the list,
and if they make a left turn keep the middle point.  If there are only
two points left, tack on the first point.&#8221;  All that remains is to
start the list with the first point and append the rest of the hull.
Here is the complete body of the function.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
grahamScan points<br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:length"><span class="kw3">length</span></a> points &lt; <span class="nu0">3</span> = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:error"><span class="kw3">error</span></a> <span class="st0">&quot;Degenerate&quot;</span><br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:otherwise"><span class="kw3">otherwise</span></a> &nbsp; &nbsp; &nbsp; &nbsp; = <br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">let</span> <span class="br0">&#40;</span>firstPoint:rest<span class="br0">&#41;</span> = findFirstPoint points<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sortedRest = sortBy <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:compare"><span class="kw3">compare</span></a> `on` <span class="br0">&#40;</span>angle firstPoint<span class="br0">&#41;</span><span class="br0">&#41;</span> rest<br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loop <span class="br0">&#40;</span>a:b:<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span> = <span class="kw1">case</span> turn a b firstPoint <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Left -&gt; b : <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp;-&gt; <span class="br0">&#91;</span><span class="br0">&#93;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; loop <span class="br0">&#40;</span>a:b:c:ps<span class="br0">&#41;</span> = <span class="kw1">case</span> turn a b c <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Left -&gt; b : loop <span class="br0">&#40;</span>b:c:ps<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; _ &nbsp; &nbsp;-&gt; loop <span class="br0">&#40;</span>a:c:ps<span class="br0">&#41;</span><br />
<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">in</span> firstPoint : loop <span class="br0">&#40;</span>firstPoint:sortedRest<span class="br0">&#41;</span><br />
&nbsp;</div>

<h3>Support</h3>

<p>Now to define the helper functions I stubbed out before.  The <code>angle</code>
function is supposed to calculate the angle between ba and the x-axis, but it&#8217;s really calculating the cosine of that angle.  Don&#8217;t tell anybody.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
angle a b = dx / len <span class="kw1">where</span><br />
&nbsp; &nbsp; dx = px a &#8211; px b<br />
&nbsp; &nbsp; dy = py a &#8211; py b<br />
&nbsp; &nbsp; len = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:sqrt"><span class="kw3">sqrt</span></a> <span class="br0">&#40;</span>dx * dx + dy * dy<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>Now the compiler says that the type parameter in our <code>Point</code> has to be
in the <code>Floating</code> class for <code>sqrt</code>.  Add that to the type declaration
of <code>grahamScan</code>.</p>

<p>The function <code>turn</code> is also simple.  If the cross product of the two
line segments is greater than zero then it is a left turn, while less than zero
is a right turn. Equal to zero is colinear, which can go either way
depending on what you want from your convex hull. I report &#8216;em all and
let the caller sort it out.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
turn a b c = <span class="kw1">case</span> <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:compare"><span class="kw3">compare</span></a> cross <span class="nu0">0</span> <span class="kw1">of</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;GT -&gt; Left<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;EQ -&gt; Colinear<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;LT -&gt; Right<br />
&nbsp; &nbsp; <span class="kw1">where</span><br />
&nbsp; &nbsp; &nbsp; cross = x1 * y2 &#8211; x2 * y1<br />
&nbsp; &nbsp; &nbsp; x1 = px b &#8211; px a<br />
&nbsp; &nbsp; &nbsp; y1 = py b &#8211; py a<br />
&nbsp; &nbsp; &nbsp; x2 = px c &#8211; px b<br />
&nbsp; &nbsp; &nbsp; y2 = py c &#8211; py b<br />
&nbsp;</div>

<p>I used <code>compare</code> here so I could use <code>case</code> instead of nested if
statements, or a function with guards.  I don&#8217;t know what the
performance differences are, I just think the code is cleaner like
this.</p>

<p>Since this function compares the values of the point coordinates,
we&#8217;ll need to add the <code>Ord</code> class to the <code>Point</code> parameter.  That goes
on <code>grahamScan</code>, which now reads</p>

<div class="dean_ch" style="white-space: wrap;"><br />
grahamScan :: <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Floating"><span class="kw4">Floating</span></a> a, <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Ord"><span class="kw4">Ord</span></a> a<span class="br0">&#41;</span> =&gt; <span class="br0">&#91;</span>Point a<span class="br0">&#93;</span> -&gt; <span class="br0">&#91;</span>Point a<span class="br0">&#93;</span><br />
&nbsp;</div>

<p>The last function, <code>firstPoint</code>, is a little tricky.  You could define
it using two passes, like this:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
findFirstPoint points =<br />
&nbsp; <span class="kw1">let</span> firstPoint = minimumBy lowerLeftCmp points<br />
&nbsp; &nbsp; &nbsp; rest = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:filter"><span class="kw3">filter</span></a> <span class="br0">&#40;</span>/= firstPoint<span class="br0">&#41;</span> points<br />
&nbsp; <span class="kw1">in</span> firstPoint:rest<br />
&nbsp;</div>

<p>However, I chose to do it in one pass by moving points from the input
list to an output list.  The lower-left point at each step is held
back and prepended to the output at the end.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
findFirstPoint points<br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:null"><span class="kw3">null</span></a> points = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:error"><span class="kw3">error</span></a> <span class="st0">&quot;Null points&quot;</span><br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:otherwise"><span class="kw3">otherwise</span></a> &nbsp; = loop points <span class="br0">&#91;</span><span class="br0">&#93;</span> <span class="kw1">where</span><br />
&nbsp; &nbsp; loop <span class="br0">&#40;</span>a:<span class="br0">&#91;</span><span class="br0">&#93;</span><span class="br0">&#41;</span> ps = a:ps<br />
&nbsp; &nbsp; loop <span class="br0">&#40;</span>a:b:rest<span class="br0">&#41;</span> ps =<br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">if</span> <span class="br0">&#40;</span>py a &lt; py b<span class="br0">&#41;</span> || <span class="br0">&#40;</span>py a == py b &amp;&amp; px a &lt; px b<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">then</span> loop <span class="br0">&#40;</span>a:rest<span class="br0">&#41;</span> <span class="br0">&#40;</span>b:ps<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw1">else</span> loop <span class="br0">&#40;</span>b:rest<span class="br0">&#41;</span> <span class="br0">&#40;</span>a:ps<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>And that&#8217;s it for a working implementation.  I also added a
convenience function for converting tuples to Points:
<code>point = uncurry Point</code>.</p>

<h3>Refinement</h3>

<p>Now we can test this out in <code>ghci</code>:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
*GrahamScan&gt; grahamScan . <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map"><span class="kw3">map</span></a> point $ <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">2</span>, <span class="nu0">3</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">-1</span>, <span class="nu0">0</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">-3</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">&#41;</span><span class="br0">&#93;</span><br />
<span class="br0">&#91;</span>Point <span class="br0">&#123;</span>px = <span class="nu0">1.0</span>, py = <span class="nu0">-3.0</span><span class="br0">&#125;</span>,Point <span class="br0">&#123;</span>px = <span class="nu0">2.0</span>, py = <span class="nu0">3.0</span><span class="br0">&#125;</span>,Point <span class="br0">&#123;</span>px = <span class="nu0">-1.0</span>, py = <span class="nu0">0.0</span><span class="br0">&#125;</span><span class="br0">&#93;</span><br />
*GrahamScan&gt; grahamScan . <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:map"><span class="kw3">map</span></a> point $ <span class="br0">&#91;</span><span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">0</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">0.5</span>, <span class="nu0">0.5</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">1</span>, <span class="nu0">1</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">0</span>, <span class="nu0">2</span><span class="br0">&#41;</span>, <span class="br0">&#40;</span><span class="nu0">-1</span>, <span class="nu0">1</span><span class="br0">&#41;</span><span class="br0">&#93;</span><br />
<span class="br0">&#91;</span>Point <span class="br0">&#123;</span>px = <span class="nu0">0.0</span>, py = <span class="nu0">0.0</span><span class="br0">&#125;</span>,Point <span class="br0">&#123;</span>px = <span class="nu0">0.5</span>, py = <span class="nu0">0.5</span><span class="br0">&#125;</span>,Point <span class="br0">&#123;</span>px = <span class="nu0">0.0</span>, py = <span class="nu0">2.0</span><span class="br0">&#125;</span>,Point <span class="br0">&#123;</span>px = <span class="nu0">-1.0</span>, py = <span class="nu0">1.0</span><span class="br0">&#125;</span><span class="br0">&#93;</span><br />
&nbsp;</div>

<p>Uh oh, there&#8217;s a bug.  The convex hull in the last test should have
included <code>(1, 1)</code> but not <code>(0.5, 0.5)</code>.  The problem is that they are
colinear with the lowest point <code>(0, 0)</code>, so they have the same angle.
They will be sorted in an arbitrary order, but whichever one ends up
first will be rejected.  To fix this, we&#8217;ll need to add the distance
to the lower-left point in the angle comparison.  If two points have
the same angle, the point that is closer should come first in the
list.  That way, it will be rejected.</p>

<p>To do this, I&#8217;ll change <code>angle</code> to return a tuple with the angle and
the length.  When comparing tuples, the elements <code>n</code> are only compared
if the elements <code>n-1</code> are equal, which is exactly what we want.  So,
with the subdefinitions the same, angle becomes:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
angle a b = <span class="br0">&#40;</span>dx / len, len<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>When I did this, I realized that I could use a tuple in the
<code>findFirstPoint</code> comparison too.  The expression:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="br0">&#40;</span>py a &lt; py b<span class="br0">&#41;</span> || <span class="br0">&#40;</span>py a == py b &amp;&amp; px a &lt; px b<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>is equivalent to</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="br0">&#40;</span>py a, px a<span class="br0">&#41;</span> &lt; <span class="br0">&#40;</span>py b, px b<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>I think the second is easier to read, and due to laziness the
x-coordinates aren&#8217;t even calculated unless the y-coordinates are
equal.</p>

<h3>Final Thoughts</h3>

<p>So that&#8217;s it really.  You can get the final source <a href="https://github.com/shadwstalkr/GrahamScanDemo">here</a>.  I
would be interested to see someone tune the performance on this.  It
scales about linearly,<sup id="fnref:timing"><a href="#fn:timing" rel="footnote">1</a></sup> which is expected since the algorithm is
O(n&nbsp;log&nbsp;n), but I think that there&#8217;s plenty of room for
improvement.  If you have some suggestions, fork <a href="https://github.com/shadwstalkr/GrahamScanDemo">the repository at Github</a> and show me what you can do.</p>

<p>Haskell&#8217;s expressive power made the implementation of this algorithm fairly easy.  There are several different ways to do it, and I&#8217;ll explore some of the options in future articles.</p>

<div class="footnotes">
<hr />
<ol>

<li id="fn:timing">
<p>These are timings for the calculation of the convex hull of sets of
random vertices.  The timings were performed on a 2.1 GHz Intel Core 2
Duo.
<table>
<thead>
<tr>
  <th>Input Vertices</th>
  <th>Time (s)</th>
</tr>
</thead>
<tbody>
<tr>
  <td>100</td>
  <td>0.013</td>
</tr>
<tr>
  <td>200</td>
  <td>0.021</td>
</tr>
<tr>
  <td>500</td>
  <td>0.037</td>
</tr>
<tr>
  <td>10000</td>
  <td>0.70</td>
</tr>
<tr>
  <td>20000</td>
  <td>1.4</td>
</tr>
<tr>
  <td>50000</td>
  <td>3.5</td>
</tr>
<tr>
  <td>100000</td>
  <td>7.0</td>
</tr>
<tr>
  <td>200000</td>
  <td>14.3</td>
</tr>
<tr>
  <td>500000</td>
  <td>37</td>
</tr>
</tbody>
</table>&#160;<a href="#fnref:timing" rev="footnote">&#8617;</a></p>
</li>

</ol>
</div>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Kb-rpg29WaQ:JG4L23SXVhk:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Kb-rpg29WaQ:JG4L23SXVhk:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Kb-rpg29WaQ:JG4L23SXVhk:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Kb-rpg29WaQ:JG4L23SXVhk:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Kb-rpg29WaQ:JG4L23SXVhk:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Kb-rpg29WaQ:JG4L23SXVhk:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Kb-rpg29WaQ:JG4L23SXVhk:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Kb-rpg29WaQ:JG4L23SXVhk:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/Kb-rpg29WaQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/graham-scan-in-haskell.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Double Pendulum Simulation</title>
		<link>http://www.tapdancinggoats.com/double-pendulum-simulation.htm</link>
		<comments>http://www.tapdancinggoats.com/double-pendulum-simulation.htm#comments</comments>
		<pubDate>Thu, 18 Aug 2011 07:53:27 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Flash]]></category>
		<category><![CDATA[Physics]]></category>
		<category><![CDATA[canvas]]></category>
		<category><![CDATA[double pendula]]></category>
		<category><![CDATA[html5]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[pendulum]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=714</guid>
		<description><![CDATA[I&#8217;ve been playing around with some of the new features in HTML5, particularly to see how the canvas stacks up to Flash. One of the things I wanted to test was javascript performance, so I ported this Flash toy I wrote a few years ago. It&#8217;s a physical simulation of a double pendulum system. It&#8217;s [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tapdancinggoats.com/double-pendula"><img src="http://www.tapdancinggoats.com/wp-content/uploads/2011/08/pendula.png" alt="" title="Double Pendula" width="421" height="392" class="alignright size-full wp-image-715" /></a></p>

<p>I&#8217;ve been playing around with some of the new features in HTML5, particularly to see how the canvas stacks up to Flash.  One of the things I wanted to test was javascript performance, so I ported this Flash toy I wrote a few years ago.  It&#8217;s a physical simulation of a double pendulum system.  It&#8217;s interactive, and it can export the line drawing it produces as a PNG.</p>

<p>How did canvas+JS do?  The export was a lot easier: I had to write a PNG encoder in Actionscript for the original version!  Pretty much everything else was harder.  Canvas has features similar to Flash 5, and I missed modern Flash&#8217;s rich standard library.  CSS layout is still somewhat inferior to Flex for GUI design, as the layout options are less flexible.</p>

<p>One of the appeals of canvas is mobile support, but I was disappointed by the performance on my Motorola Droid.  Just clearing the background on a canvas larger than 500&#215;200 took the frame rate to single digits, and I couldn&#8217;t find a reliable way to make the canvas fill the screen if other elements were present (I didn&#8217;t look too hard, since a canvas that large was unusable).  The javascript performance was fine, it was just the drawing that caused problems.  Let me know if you get better results on different hardware, I&#8217;d love to know that this can work better.</p>

<p>Overall, canvas shows promise, but I don&#8217;t think it&#8217;s ready to replace Flash for complex graphical applications.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Z_m0E46HkDU:05TEXw3Wh1o:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Z_m0E46HkDU:05TEXw3Wh1o:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Z_m0E46HkDU:05TEXw3Wh1o:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Z_m0E46HkDU:05TEXw3Wh1o:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Z_m0E46HkDU:05TEXw3Wh1o:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Z_m0E46HkDU:05TEXw3Wh1o:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=Z_m0E46HkDU:05TEXw3Wh1o:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=Z_m0E46HkDU:05TEXw3Wh1o:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/Z_m0E46HkDU" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/double-pendulum-simulation.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Apocalypse</title>
		<link>http://www.tapdancinggoats.com/apocalypse.htm</link>
		<comments>http://www.tapdancinggoats.com/apocalypse.htm#comments</comments>
		<pubDate>Thu, 18 Aug 2011 03:03:29 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Politics]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=705</guid>
		<description><![CDATA[Why do people speak of the apocalypse as a discrete, identifiable event? We will not stare in horror as the sky splits open, pouring hordes upon us. Do you think the Romans or the Chinese recognized the beginning of the end of their empire? History suggests that they didn&#8217;t even recognize the middle of the [...]]]></description>
			<content:encoded><![CDATA[<p>Why do people speak of the apocalypse as a discrete, identifiable event?  We will not stare in horror as the sky splits open, pouring hordes upon us.  Do you think the Romans or the Chinese recognized the beginning of the end of their empire?  History suggests that they didn&#8217;t even recognize the middle of the end.  Look around.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=TneVQrsnrXo:OK_LDWX5kYo:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=TneVQrsnrXo:OK_LDWX5kYo:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=TneVQrsnrXo:OK_LDWX5kYo:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=TneVQrsnrXo:OK_LDWX5kYo:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=TneVQrsnrXo:OK_LDWX5kYo:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=TneVQrsnrXo:OK_LDWX5kYo:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=TneVQrsnrXo:OK_LDWX5kYo:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=TneVQrsnrXo:OK_LDWX5kYo:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/TneVQrsnrXo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/apocalypse.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Windows vs. Unix File System Semantics – Conifer Systems</title>
		<link>http://www.tapdancinggoats.com/windows-vs-unix-file-system-semantics-conifer-systems.htm</link>
		<comments>http://www.tapdancinggoats.com/windows-vs-unix-file-system-semantics-conifer-systems.htm#comments</comments>
		<pubDate>Fri, 15 Jul 2011 01:43:25 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[file system]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[win32]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=701</guid>
		<description><![CDATA[This is a great summary of the low-level API differences between Windows and Linux file systems. Windows vs. Unix File System Semantics &#8211; Conifer Systems.]]></description>
			<content:encoded><![CDATA[<p>This is a great summary of the low-level API differences between Windows and Linux file systems.</p>

<p><a href="http://www.conifersystems.com/2008/10/21/windows-vs-unix-file-system-semantics/">Windows vs. Unix File System Semantics &#8211; Conifer Systems</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=WrWFR2boPd8:BKTsoXQva_c:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=WrWFR2boPd8:BKTsoXQva_c:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=WrWFR2boPd8:BKTsoXQva_c:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=WrWFR2boPd8:BKTsoXQva_c:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=WrWFR2boPd8:BKTsoXQva_c:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=WrWFR2boPd8:BKTsoXQva_c:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=WrWFR2boPd8:BKTsoXQva_c:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=WrWFR2boPd8:BKTsoXQva_c:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/WrWFR2boPd8" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/windows-vs-unix-file-system-semantics-conifer-systems.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Practical Haskell: scripting with types</title>
		<link>http://www.tapdancinggoats.com/practical-haskell-scripting-with-types.htm</link>
		<comments>http://www.tapdancinggoats.com/practical-haskell-scripting-with-types.htm#comments</comments>
		<pubDate>Fri, 01 Jul 2011 10:32:43 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Links]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Don Stewart]]></category>
		<category><![CDATA[haskell]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=699</guid>
		<description><![CDATA[Starting with a simple shell script, Don Stewart shows how Haskell can be readable, safe, and robust in this slide show. Practical Haskell: scripting with types « Control.Monad.Writer.]]></description>
			<content:encoded><![CDATA[<p>Starting with a simple shell script, Don Stewart shows how Haskell can be readable, safe, and robust in this slide show.</p>

<p><a href="http://donsbot.wordpress.com/2010/08/17/practical-haskell/">Practical Haskell: scripting with types « Control.Monad.Writer</a>.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=o64TnMxOnZQ:1RqSJVrXzv0:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=o64TnMxOnZQ:1RqSJVrXzv0:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=o64TnMxOnZQ:1RqSJVrXzv0:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=o64TnMxOnZQ:1RqSJVrXzv0:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=o64TnMxOnZQ:1RqSJVrXzv0:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=o64TnMxOnZQ:1RqSJVrXzv0:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=o64TnMxOnZQ:1RqSJVrXzv0:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=o64TnMxOnZQ:1RqSJVrXzv0:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/o64TnMxOnZQ" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/practical-haskell-scripting-with-types.htm/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fox &amp; Geese in Haskell: Part 2</title>
		<link>http://www.tapdancinggoats.com/fox-geese-in-haskell-part-2.htm</link>
		<comments>http://www.tapdancinggoats.com/fox-geese-in-haskell-part-2.htm#comments</comments>
		<pubDate>Tue, 28 Jun 2011 03:53:45 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Games]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[fox and geese]]></category>
		<category><![CDATA[haskell]]></category>
		<category><![CDATA[monads]]></category>

		<guid isPermaLink="false">http://www.tapdancinggoats.com/?p=684</guid>
		<description><![CDATA[Last time we looked at how the board is represented in the little Fox &#38; Geese game I wrote in Haskell. This time, I&#8217;ll cover the machinery that makes the game go: moving pieces, jumping, and validating moves. The code for this part is available in my GitHub repo under tag v0.1.2. To simplify the [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.tapdancinggoats.com/fox-geese-in-haskell-part-1.htm">Last time</a> we looked at how the board is represented in the
little <a href="http://en.wikipedia.org/wiki/Fox_and_geese">Fox &amp; Geese</a> game I wrote in <a href="http://www.haskell.org/">Haskell</a>.  This
time, I&#8217;ll cover the machinery that makes the game go: moving pieces,
jumping, and validating moves.  The code for this part is available in
<a href="https://github.com/shadwstalkr/fox_and_geese">my GitHub repo</a> under tag <em>v0.1.2</em>.</p>

<p><span id="more-684"></span></p>

<p>To simplify the game mechanic functions, we&#8217;ll carry the game state
around in a <code>State</code> monad called <code>GameStateM</code>.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="kw1">type</span> GameStateM a = State GameState a<br />
&nbsp;</div>

<p>This is created by the input functions that we&#8217;ll see later.</p>

<p>The first thing we want is a high-level function that can be used to
move a piece.  This is easy to describe in plain English: if the move
from space A to space B is valid, move the piece on the board and
remove any piece that was jumped, then it&#8217;s the next player&#8217;s turn.
It is almost as easy to write in Haskell:</p>

<div class="dean_ch" style="white-space: wrap;"><br />
movePiece :: Position -&gt; Position -&gt; GameStateM <span class="br0">&#40;</span><span class="br0">&#41;</span><br />
movePiece from to = <span class="kw1">do</span><br />
&nbsp; <span class="br0">&#40;</span>valid, jumped<span class="br0">&#41;</span> &lt;- isMoveValid from to<br />
&nbsp; when valid $ <span class="kw1">do</span><br />
&nbsp; &nbsp; oldBoard &lt;- gets board<br />
&nbsp; &nbsp; <span class="kw1">let</span> newBoard = jumpPiece jumped . move $ oldBoard<br />
&nbsp; &nbsp; modify $ \game -&gt; game <span class="br0">&#123;</span>board = newBoard<span class="br0">&#125;</span><br />
&nbsp; &nbsp; switchPlayer<br />
&nbsp; selectPosition Nothing<br />
&nbsp;</div>

<p>We&#8217;ll look at <code>isMoveValid</code> soon.  When the move is valid, this gets the board from the current state, makes a new board with the pieces moved, then puts the new board back in the state.  The function <code>gets board</code> maps the projection <code>board</code> into the state,
so it is equivalent to <code>get &gt;&gt;= return . board</code>.  We put the new board
back into the state with <code>modify</code>, which takes a function that
modifies the current state.  So <code>modify f</code> is equivalent to
<code>get &gt;&gt;= put . f</code>.  We&#8217;ll look at <code>switchPlayer</code> and <code>selectPosition</code>
in the part about input.</p>

<p>Now, let&#8217;s define <code>move</code> and <code>jumpPiece</code>.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
move board&#8217; = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:maybe"><span class="kw3">maybe</span></a> board&#8217; <span class="br0">&#40;</span>boardAfterMove board&#8217;<span class="br0">&#41;</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <span class="br0">&#40;</span>getPiece&#8217; from board&#8217;<span class="br0">&#41;</span><br />
<br />
boardAfterMove board&#8217; piece = Map.insert to piece <br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; . Map.delete from $ board&#8217;<br />
&nbsp;</div>

<p>In <code>move</code> we first try to get the moving piece from the board.  If it
existed, we return the board with the piece moved.  To do that, we
delete the piece from the old position and insert it at the new one.</p>

<p>Next, we take a leap.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="co1">&#8211; jumpPiece :: Maybe Position -&gt; Board -&gt; Board</span><br />
jumpPiece Nothing = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:id"><span class="kw3">id</span></a><br />
jumpPiece <span class="br0">&#40;</span>Just pos<span class="br0">&#41;</span> = Map.delete pos<br />
&nbsp;</div>

<p>Notice that these are partial functions.  If the position that was
jumped is <code>Nothing</code>, i.e. no jump, then don&#8217;t modify the board.
Otherwise, delete the piece that was jumped.</p>

<p>Now the hard part: checking if the move is valid.  We have a number of
things to check here, so let&#8217;s break it down.  A move is valid if:</p>

<ul>
<li>The destination is on the board</li>
<li>The destination space is empty</li>
<li>If the piece that is moving is a goose, then it must move forward</li>
<li>The spaces have to be adjacent or a jump</li>
<li>A jump can only occur if the destination is two spaces away from the
start along a line, and the moving piece is a fox, and the space
jumped had a goose, and the first two rules still apply</li>
</ul>

<p>Whew, that&#8217;s a lot to check.  Let&#8217;s start.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
isMoveValid :: Position -&gt; Position -&gt; GameStateM <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Bool"><span class="kw4">Bool</span></a>, <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#t:Maybe"><span class="kw4">Maybe</span></a> Position<span class="br0">&#41;</span><br />
isMoveValid from@<span class="br0">&#40;</span>fx, fy<span class="br0">&#41;</span> to@<span class="br0">&#40;</span>tx, ty<span class="br0">&#41;</span> = <span class="kw1">do</span><br />
&nbsp; Just movingPiece &lt;- gets $ getPiece from<br />
&nbsp; destinationIsEmpty &lt;- <span class="br0">&#40;</span><a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:not"><span class="kw3">not</span></a> . Map.member to<span class="br0">&#41;</span> &lt;$&gt; gets board<br />
&nbsp; isJump &lt;- isGoose . jumpedPos $ movingPiece<br />
&nbsp; <br />
&nbsp; valid &lt;- <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> $ <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:and"><span class="kw3">and</span></a> <span class="br0">&#91;</span>onBoard,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;movingPiece == Fox || movingForward,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;destinationIsEmpty,<br />
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;isAdjacent || isJump<span class="br0">&#93;</span><br />
<br />
&nbsp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> <span class="br0">&#40;</span>valid, jumpedPos movingPiece<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>We&#8217;ll need to know what piece is moving in a few places, so get it
here.  It also helps to get what we need from the state here, so we
can define helper functions which aren&#8217;t in the state monad.  Next, we
check if the destination is empty with <code>Map.member</code>.  Remember, we
don&#8217;t store empty spaces in the map.  We use a couple of helper
functions to check if the move is a jump, then we combine all of our
rules in a call to <code>and</code>.  Finally, the result of the function is if
the move is valid and which space was jumped, if any.</p>

<p>Let&#8217;s dive into these helper functions.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
dx = tx &#8211; fx<br />
dy = ty &#8211; fy<br />
onBoard = to `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:elem"><span class="kw3">elem</span></a>` validPositions<br />
isAdjacent = to `<a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:elem"><span class="kw3">elem</span></a>` adjacentPositions from<br />
movingForward = dy &gt;= <span class="nu0">0</span><br />
<br />
<span class="co1">&#8211; isGoose :: Maybe Position -&gt; GameStateM Bool</span><br />
isGoose Nothing = <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:return"><span class="kw3">return</span></a> False<br />
isGoose <span class="br0">&#40;</span>Just pos<span class="br0">&#41;</span> = <span class="br0">&#40;</span>Just Goose ==<span class="br0">&#41;</span> &lt;$&gt; <span class="br0">&#40;</span>gets $ getPiece pos<span class="br0">&#41;</span><br />
&nbsp;</div>

<p>These are all very simple definitions.  We need <code>dx</code> and <code>dy</code> in a lot
of places, so they&#8217;re defined here.  <code>onBoard</code> and <code>isAdjacent</code> use
two definitions from <a href="http://www.tapdancinggoats.com/fox-geese-in-haskell-part-1.htm">part 1</a>.  The function <code>isGoose</code> checks
if a jumped space has a goose.  How do we calculate the jumped space?
We know that it has to be either two positions up, down, or sideways,
and if <code>(x + y)</code> is even then we can go diagonally also.</p>

<div class="dean_ch" style="white-space: wrap;"><br />
<span class="co1">&#8211; jumpedPos :: Side -&gt; Maybe Position</span><br />
jumpedPos Fox<br />
&nbsp; &nbsp; <span class="co1">&#8211; Straight up or down</span><br />
&nbsp; &nbsp; | dx == <span class="nu0">0</span> &amp;&amp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:abs"><span class="kw3">abs</span></a> dy == <span class="nu0">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; = Just <span class="br0">&#40;</span>fx, fy + <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:signum"><span class="kw3">signum</span></a> dy<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">&#8211; Sideways</span><br />
&nbsp; &nbsp; | dy == <span class="nu0">0</span> &amp;&amp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:abs"><span class="kw3">abs</span></a> dx == <span class="nu0">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; = Just <span class="br0">&#40;</span>fx + <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:signum"><span class="kw3">signum</span></a> dx, fy<span class="br0">&#41;</span><br />
&nbsp; &nbsp; <span class="co1">&#8211; Diagonally</span><br />
&nbsp; &nbsp; | <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:even"><span class="kw3">even</span></a> <span class="br0">&#40;</span>fx + fy<span class="br0">&#41;</span> &amp;&amp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:abs"><span class="kw3">abs</span></a> dx == <span class="nu0">2</span> &amp;&amp; <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:abs"><span class="kw3">abs</span></a> dy == <span class="nu0">2</span><br />
&nbsp; &nbsp; &nbsp; &nbsp; = Just <span class="br0">&#40;</span>fx + <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:signum"><span class="kw3">signum</span></a> dx, fy + <a href="http://haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v:signum"><span class="kw3">signum</span></a> dy<span class="br0">&#41;</span><br />
jumpedPos _ = Nothing<br />
&nbsp;</div>

<p>If the jumping piece isn&#8217;t a fox, or the move isn&#8217;t a jump, return
<code>Nothing</code>.</p>

<p>This is the bare minimum of mechanics for a working fox and geese
game.  It&#8217;s actually not complete, because we don&#8217;t allow multiple
jumps, and we don&#8217;t force a player to take a jump if he can.  I will
add those later and write a new post.</p>

<p>Next time, we&#8217;ll see how to make our game interact with the world,
with input and drawing.  The source code is
<a href="https://github.com/shadwstalkr/fox_and_geese">available on GitHub</a>, so please fork it and make it better.</p>
<div class="feedflare">
<a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tO4-7xMnVYo:WBnszI4qVN8:yIl2AUoC8zA"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=yIl2AUoC8zA" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tO4-7xMnVYo:WBnszI4qVN8:F7zBnMyn0Lo"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tO4-7xMnVYo:WBnszI4qVN8:F7zBnMyn0Lo" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tO4-7xMnVYo:WBnszI4qVN8:V_sGLiPBpWU"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tO4-7xMnVYo:WBnszI4qVN8:V_sGLiPBpWU" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tO4-7xMnVYo:WBnszI4qVN8:qj6IDK7rITs"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?d=qj6IDK7rITs" border="0"></img></a> <a href="http://feeds.feedburner.com/~ff/Tapdancinggoats?a=tO4-7xMnVYo:WBnszI4qVN8:gIN9vFwOqvQ"><img src="http://feeds.feedburner.com/~ff/Tapdancinggoats?i=tO4-7xMnVYo:WBnszI4qVN8:gIN9vFwOqvQ" border="0"></img></a>
</div><img src="http://feeds.feedburner.com/~r/Tapdancinggoats/~4/tO4-7xMnVYo" height="1" width="1"/>]]></content:encoded>
			<wfw:commentRss>http://www.tapdancinggoats.com/fox-geese-in-haskell-part-2.htm/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
	</channel>
</rss>

