tag:blogger.com,1999:blog-168463332024-03-13T10:27:38.746-05:00λόγοςThought. Reckoning. Meaning. Reasoning. Word.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.comBlogger123125tag:blogger.com,1999:blog-16846333.post-63021891005056042662011-04-29T18:06:00.002-05:002011-04-29T18:17:22.711-05:00Considering a gas-powered standby generator<div>
I've been wearing my <a href="http://bowilliams.com/">Bo Williams</a> Risk Analysis™ cap a fair amount for the past couple of days, and this post started life as a comment on his post <a href="http://bowilliams.com/2011/04/friday-miscellanea-post-alabama-tornado-super-outbreak-edition/">Friday miscellanea, post-Alabama tornado super-outbreak edition</a>.</div>
<div>
<br /></div>
<div>
Our house has gas heat and a gas set in the fireplace. I've been letting the latter slide in a state of disrepair. I recognize and accept this BWRA™ Demerit. It will be ready before winter 2011, which will mean redundant sources of heat. You ought to see my related <a href="http://www.davidco.com/">GTD</a> project list!</div>
<div>
<br /></div>
<div>
The option is obvious now, but it took a conversation with my dad to learn about permanent standby generators that run on natural gas and periodically test themselves. I priced them online and may be able to purchase a unit that would power most of my house, perhaps in staggered operation for heavy loads such as HVAC and dryer, for around $5k with no headaches of managing a gasoline reserve or just-in-time fuel purchases.</div>
<div>
<br /></div>
<div>
The last week-long outage in the area was nearly forty years ago, but sidestepping even hours-long outages due to storms, ice on power lines, drunks hitting poles, and so on is awfully appealing too. I emptied the refrigerator and freezer, and temperatures in the Huntsville area are projected to be mild. My one power-related worry is my 55-gallon cichlid tank. I turned on a battery-powered air pump, but that's about the best I could do. I think I was a week overdue for a water change when we lost power, so staying on top of aquarium chores in the future will help there too, assuming optimistically that these hardy critters make it.</div>
<div>
<br /></div>
<div>
Other questions:</div>
<div>
<ul>
<li>Where can I find comprehensive lists of electrical and gas outages to find whether I'm trading more-or-less equivalent problems?</li>
<li>How expensive would backup mode be?</li>
<li>Fossil fuels in general aren't getting any cheaper, so at what gas price does such a generator become a total dud?</li>
<li>What about purification of, say, rain water?</li>
<li>I expect a crazy run on generators when we're no longer part of the third world. What are good value metrics?</li>
<li>What other issues do I need to consider?</li>
</ul>
</div>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com5tag:blogger.com,1999:blog-16846333.post-43270582999615824522011-04-23T15:09:00.000-05:002011-04-23T15:09:58.415-05:00Are coaches to blame for the awful new taunting rule?In <a href="http://claytravis.net/wordpress/?p=1316">What if you were an SEC Official For a Day? (Part One)</a>, Clay Travis blames NCAA coaches for the new rule that allows officials to take points off the board and even eject players for behavior deemed to be taunting.<br />
<blockquote>
But officials believe that the coaches, who are the ones who actually make the rules, have foisted the enforcement of taunting onto the officials to relieve pressure on themselves. That is, coaches can point to the officials as the bad guys who are keeping the players from taunting. Effectively, multi-million dollar coaches are ducking the obligation to discipline their teams onto part-time officials. </blockquote>
<blockquote>
As Steve Shaw notes, “Coaches write the rules. They want it. They control it.” … </blockquote>
<blockquote>
The outrage should go to the coaches who implemented this rule. They did it because they don’t want to be the sheriffs. They want to blame the officials for not letting the players celebrate. And, by the way, do you know who will lead the charge in criticizing officials when this call is made to his team’s detriment? </blockquote>
<blockquote>
Yep, the head coach who voted to make this a rule in the first place.</blockquote>
I don't buy this for a second. I'd like to see a rollcall vote from head coaches of major NCAA programs on whether they want this awful rule. These guys risk permanent facial disfigurement screaming at players who invite stupid showboating flags in critical situations—hardly a consensus endorsement.<br />
<br />
In defense of players, controlling emotion can be really difficult. Any fan has been in the situation of hugging the guy next to him after a big stop in a tense situation. Now for the player sweating and bleeding in the trenches who breaks the go-ahead TD or comes up with a pick deep in his own territory, <i>of course</i> he's going to be elated and <i>especially</i> in big, high-pressure games. The players' passion is a wonderful distinguishing feature of NCAA football.<br />
<br />
The biggest flaw of the rule is that it conflates celebration and taunting. Yes, there are cases were players have engaged in unsportsmanlike taunting meant to demean opponents, but I'd be surprised if these were anything other than a tiny minority. A study segregating celebration flags into piles of behavior intended to deride the guys on the other side versus spontaneous joy of accomplishment, although highly subjective, would be an interesting result. Anyone interested in collaborating on <a href="http://tauntingornot.com/">tauntingornot.com</a>?<br />
<br />
This looks like another hook to give officials even more influence over games' outcomes. Some pencil-necked geek on the make at the corrupt NCAA is behind this.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-51107571399109508202011-02-28T20:56:00.004-06:002011-02-28T21:25:28.064-06:00Extracting comma-separated integers with PerlA friend writes asking whether
<br />
<pre><span style="font-family: monospace;"><span style="color: brown;"><b>my</b></span> <span style="color: darkcyan;">@data</span> = ( <span style="color: darkcyan;">$data</span> =~ m|(-?\d+),(-?\d+),(\-?\d+)\r| );</span></pre>
or
<br />
<pre><span style="font-family: monospace;">(<span style="color: darkcyan;">$data</span>) = (<span style="color: brown;"><b>split</b></span> <span style="color: magenta;">"</span><span style="color: slateblue;">\r</span><span style="color: magenta;">"</span>, <span style="color: darkcyan;">$data</span>);
<span style="color: brown;"><b>my</b></span> <span style="color: darkcyan;">@data</span> = <span style="color: brown;"><b>split</b></span> <span style="color: magenta;">'</span><span style="color: magenta;">,</span><span style="color: magenta;">'</span>, <span style="color: darkcyan;">$data</span>;</span></pre>
would be better for extracting integers from a line of input, and my reply is below.<br />
<br />
The best approach depends on a few factors. Who generates the data you're processing? How much slop in the input format do you need to accommodate? How flexible do you need to be with respect to future changes in the input, e.g., extra fields, different types, and so on?<br />
<br />
The CR (<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">\r</span>) in your input is a red flag. Are you running on a Unix platform with input generated on Windows? Can you be more specific about “possibly some other stuff” after the comma-separated numbers?<br />
<br />
Perl's <a href="http://perldoc.perl.org/perlvar.html#%24%2f"><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$/</span> special variable</a> can handle oddball line endings. Its default value varies with what makes sense for the current platform: e.g., <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">\n</span> on Unix and <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">\r\n</span> on Windows. Macs introduce another twist (see <a href="http://perldoc.perl.org/perlport.html#Newlines">Newlines in the perlport documentation</a>), but I assume you're not using that platform.<br />
<br />
On Windows for files opened in text mode (the default), the C library silently transforms CR followed by LF into LF, so if this matches your setup, I'm surprised you're seeing the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">\r</span><span class="Apple-style-span" style="font-family: inherit;"> at all</span>.<br />
<br />
Say your input is plain text generated on Windows, and you're running on Linux. Then you'd process it with code of the form<br />
<pre><span style="font-family: monospace;"><span style="color: darkcyan;">$/</span> = <span style="color: magenta;">"</span><span style="color: slateblue;">\r\n</span><span style="color: magenta;">"</span>;
<span style="color: brown;"><b>while</b></span> (<span style="color: brown;"><b>defined</b></span>(<span style="color: darkcyan;">$data</span> = <span style="color: darkcyan"><></span>)) {
<span style="color: brown;"><b>chomp</b></span>;
...;
}</span></pre>
Remember that <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"><a href="http://perldoc.perl.org/functions/chomp.html">chomp</a></span> removes the value of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$/</span> from the end of the target.<br />
<br />
As for extracting the data, <a href="http://www.stonehenge.com/merlyn/">Randal Schwartz</a> (author of <i><a href="http://oreilly.com/catalog/9780596520113">Learning Perl</a></i>, a.k.a. the llama book) has a rule of thumb:<br />
<blockquote>
<span class="Apple-style-span" style="font-family: inherit;">Use capturing or <tt>m//g</tt> when you know what you want to <b>keep</b>.</span><br /><span class="Apple-style-span" style="font-family: inherit;">Use <tt>split</tt> when you know what you want to <b>throw away</b>.</span></blockquote>
I first saw this useful guideline in <a href="http://perl.plover.com/yak/regex/samples/slide070.html">“Regular Expression Mastery” by Mark Dominus</a>.<br />
<br />
If this is a quick-and-dirty utility, I'd be inclined to write<br />
<pre><span style="font-family: monospace;"><span style="color: darkcyan;">@data</span> = <span style="color: brown;"><b>split</b></span><span style="color: brown;"><b> /</b></span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: magenta;">,</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: brown;"><b>/</b></span>, <span style="color: darkcyan;">$data</span>;</span></pre>
This allows for and removes any whitespace around the commas.<br />
<br />
If it's important to nail down the format (maybe as a sanity check that you're in the section of the config file where you think you are), you could write<br />
<pre><span style="font-family: monospace;"><span style="color: brown;"><b>if</b></span> (<span style="color: darkcyan;">$data</span> =~<span style="color: brown;"><b> /</b></span><span style="color: magenta;">^</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*(</span><span style="color: magenta;">-</span><span style="color: slateblue;">?</span><span style="color: slateblue;">\d</span><span style="color: slateblue;">+)</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: magenta;">,</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*(</span><span style="color: magenta;">-</span><span style="color: slateblue;">?</span><span style="color: slateblue;">\d</span><span style="color: slateblue;">+)</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: magenta;">,</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*(</span><span style="color: magenta;">-</span><span style="color: slateblue;">?</span><span style="color: slateblue;">\d</span><span style="color: slateblue;">+)</span><span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: magenta;">$</span><span style="color: brown;"><b>/</b></span>) {
<span style="color: brown;"><b>my</b></span>(<span style="color: darkcyan;">$x</span>,<span style="color: darkcyan;">$y</span>,<span style="color: darkcyan;">$z</span>) = (<span style="color: darkcyan;">$1</span>,<span style="color: darkcyan;">$2</span>,<span style="color: darkcyan;">$3</span>);
...;
}
<span style="color: brown;"><b>else</b></span> {
<span style="color: brown;"><b>die</b></span> <span style="color: magenta;">"</span><span style="color: darkcyan;">$0</span><span style="color: magenta;">: </span><span style="color: darkcyan;">$ARGV</span><span style="color: magenta;">:</span><span style="color: darkcyan;">$.</span><span style="color: magenta;">: unexpected format</span><span style="color: magenta;">"</span>;
}</span></pre>
Note the use of <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">$1</span> and friends inside the conditional only. Always, always, always protect uses of capture variables with conditionals.<br />
<br />
The pattern is just at the annoyance threshold of repetition and illegibility. Perl version 5.10 opens up nice possibilities with <a href="http://perldoc.perl.org/perlre.html#Capture-buffers">named capture buffers</a>:
<pre><span style="font-family: monospace;"><span style="color: #a020f0;">#! /usr/bin/perl</span>
<span style="color: brown;"><b>use strict</b></span>;
<span style="color: brown;"><b>use warnings</b></span>;
<span style="color: brown;"><b>use </b></span><span style="color: magenta;">5.10</span>.<span style="color: magenta;">0</span>;
<span style="color: brown;"><b>my</b></span> <span style="color: darkcyan;">$record</span> = <span style="color: magenta;">qr/</span>
<span style="color: magenta;"> ^</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;">&ws</span><span style="color: slateblue;">)</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><num></span><span style="color: slateblue;">(?</span><span style="color: magenta;">&n</span><span style="color: slateblue;">))</span><span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;">&sep</span><span style="color: slateblue;">)</span><span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><num></span><span style="color: slateblue;">(?</span><span style="color: magenta;">&n</span><span style="color: slateblue;">))</span><span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;">&sep</span><span style="color: slateblue;">)</span><span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><num></span><span style="color: slateblue;">(?</span><span style="color: magenta;">&n</span><span style="color: slateblue;">))</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;">&ws</span><span style="color: slateblue;">)</span>
<span style="color: magenta;"> $</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?(</span><span style="color: magenta;">DEFINE</span><span style="color: slateblue;">)</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><n></span> <span style="color: slateblue;">-?</span><span style="color: magenta;"> </span><span style="color: slateblue;">\d</span><span style="color: slateblue;">+)</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><ws></span> <span style="color: slateblue;">\s</span><span style="color: slateblue;">*</span><span style="color: magenta;"> </span><span style="color: slateblue;">)</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">(?</span><span style="color: magenta;"><sep></span> <span style="color: slateblue;">(?</span><span style="color: magenta;">&ws</span><span style="color: slateblue;">)</span><span style="color: magenta;"> , </span><span style="color: slateblue;">(?</span><span style="color: magenta;">&ws</span><span style="color: slateblue;">))</span>
<span style="color: magenta;"> </span><span style="color: slateblue;">)</span>
<span style="color: magenta;">/x</span>;
<span style="color: brown;"><b>while</b></span> (<span style="color: darkcyan;"><DATA></span>) {
<span style="color: brown;"><b>if</b></span> (<span style="color: brown;"><b>/</b></span><span style="color: darkcyan;">$record</span><span style="color: brown;"><b>/</b></span>) {
<span style="color: brown;"><b>my</b></span>(<span style="color: darkcyan;">$x</span>,<span style="color: darkcyan;">$y</span>,<span style="color: darkcyan;">$z</span>) = @{ <span style="color: darkcyan;">$-</span>{num} };
<span style="color: brown;"><b>print</b></span> <span style="color: magenta;">"</span><span style="color: magenta;">got: x=</span><span style="color: darkcyan;">$x</span><span style="color: magenta;">, y=</span><span style="color: darkcyan;">$y</span><span style="color: magenta;">, z=</span><span style="color: darkcyan;">$z</span><span style="color: slateblue;">\n</span><span style="color: magenta;">"</span>;
}
<span style="color: brown;"><b>else</b></span> {
<span style="color: brown;"><b>warn</b></span> <span style="color: magenta;">"</span><span style="color: darkcyan;">$0</span><span style="color: magenta;">: line </span><span style="color: darkcyan;">$.</span><span style="color: magenta;">: no match</span><span style="color: slateblue;">\n</span><span style="color: magenta;">"</span>;
}
}
<span style="color: blue;">__DATA__</span>
<span style="color: blue;">1,2,3</span>
<span style="color: blue;">4,5,6</span>
<span style="color: blue;">7,8</span>
</span></pre>
Its output:<br />
<pre><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">got: x=1, y=2, z=3</span>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">got: x=4, y=5, z=6</span>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">./prog: line 3: no match</span>
<span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"></span></pre>
<span class="Apple-style-span" style="font-family: inherit;">Notice its use of </span><a href="http://perldoc.perl.org/perlvar.html#%25-"><span class="Apple-style-span" style="font-family: inherit;">the special </span><span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">%-</span><span class="Apple-style-span" style="font-family: inherit;"> hash</span></a><span class="Apple-style-span" style="font-family: inherit;"> that records all captures named “num” in this case. With </span><a href="http://perldoc.perl.org/perlre.html#(DEFINE)" style="font-family: 'Courier New', Courier, monospace;">(DEFINE)</a>, subpatterns get meaningful names, and the <span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;">/x</span> modifier allow for judicious use of whitespace inside the pattern.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com1tag:blogger.com,1999:blog-16846333.post-29254692521856401892010-12-31T21:00:00.000-06:002010-12-31T21:00:46.127-06:00Checkers game-over in Haskell<p>The programming subreddit recently had a discussion about <a href="http://www.reddit.com/r/compsci/comments/esbpe/anyone_have_a_good_algorithm_for_checking_the/">testing a checkers board for game-over</a>. I wondered how specifying the rules for legal moves would look with <a href="http://haskell.org/tutorial/patterns.html">Haskell's pattern matching</a>, and this post is a study of that technique. In fact, you can run yourself. Copy-and-paste the post body to a file named <tt>Checkers.lhs</tt> to get a working program!</p>
<p>The game is <a href="http://en.wikipedia.org/wiki/English_draughts">American checkers</a> or English draughts, played on an eight-by-eight checkerboard, of all surfaces.</p>
<pre><span class='varop'>></span> <span class='comment'>{-# LANGUAGE ViewPatterns #-}</span>
</pre>
<pre><span class='varop'>></span> <span class='keyword'>module</span> <span class='conid'>Checkers</span> <span class='keyword'>where</span>
</pre>
<pre><span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Data</span><span class='varop'>.</span><span class='conid'>Char</span> <span class='layout'>(</span><span class='varid'>toLower</span><span class='layout'>,</span><span class='varid'>toUpper</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Data</span><span class='varop'>.</span><span class='conid'>List</span> <span class='layout'>(</span><span class='varid'>tails</span><span class='layout'>,</span><span class='varid'>transpose</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Test</span><span class='varop'>.</span><span class='conid'>HUnit</span>
</pre>
<pre><span class='varop'>></span> <span class='keyword'>data</span> <span class='conid'>Board</span> <span class='keyglyph'>=</span> <span class='conid'>Board</span> <span class='keyglyph'>[</span><span class='conid'>String</span><span class='keyglyph'>]</span> <span class='keyword'>deriving</span> <span class='layout'>(</span><span class='conid'>Show</span><span class='layout'>)</span>
</pre>
<pre><span class='varop'>></span> <span class='definition'>size</span> <span class='keyglyph'>::</span> <span class='conid'>Int</span>
<span class='varop'>></span> <span class='definition'>size</span> <span class='keyglyph'>=</span> <span class='num'>8</span>
</pre>
<p>For a rough idea of the punchline, I was hoping for code along the lines of</p>
<pre><span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'w'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'w'</span><span class='conop'>:</span><span class='chr'>'b'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'w'</span><span class='conop'>:</span><span class='chr'>'B'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='chr'>'b'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='chr'>'B'</span><span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span><span class='chr'>'b'</span><span class='conop'>:</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span><span class='chr'>'B'</span><span class='conop'>:</span><span class='chr'>'W'</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='definition'>move</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='num'>0</span></pre>
<p>and eventually</p>
<pre><span class='varop'>></span> <span class='definition'>gameOver</span> <span class='keyglyph'>::</span> <span class='conid'>Board</span> <span class='keyglyph'>-></span> <span class='conid'>Bool</span>
<span class='varop'>></span> <span class='definition'>gameOver</span> <span class='varid'>b</span> <span class='keyglyph'>=</span> <span class='varid'>blueMoves</span> <span class='varid'>b</span> <span class='varop'>==</span> <span class='num'>0</span> <span class='varop'>||</span> <span class='varid'>whiteMoves</span> <span class='varid'>b</span> <span class='varop'>==</span> <span class='num'>0</span>
</pre>
<p>The OP on reddit chose white and blue for the sides' colors, and above we have more-or-less declarative rules for legal white moves. A pawn or king (<tt>w</tt> and <tt>W</tt> respectively) can move to an empty space before it. Kings are special in that they can move backwards. The list ends with legal jumps, and everything else is invalid.</p>
<p>The code is repetitive, but I'll clean that up later.</p>
<p>An immediate problem is the patterns are linear, but all legal moves in checkers are along diagonals. I kicked around ideas such as using <a href="http://en.wikibooks.org/wiki/Haskell/Hierarchical_libraries/Arrays">IArray</a> or nasty double-applications of <a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:-33--33-"><tt>!!</tt></a>. Then I realized I could rotate the board by 45° with a shear, a transposition, and removal of placeholders.</p>
<pre><span class='comment'>-- diagonals with positive slopes</span>
<span class='definition'>posdiags</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='varid'>reverse</span> <span class='varop'>.</span> <span class='varid'>filter</span> <span class='varid'>used</span> <span class='varop'>.</span> <span class='varid'>transpose</span> <span class='varop'>.</span> <span class='varid'>map</span> <span class='varid'>shear</span> <span class='varop'>.</span> <span class='varid'>zip</span> <span class='keyglyph'>[</span><span class='num'>0</span><span class='keyglyph'>..</span><span class='keyglyph'>]</span>
<span class='keyword'>where</span> <span class='varid'>shear</span> <span class='layout'>(</span><span class='varid'>i</span><span class='layout'>,</span><span class='varid'>s</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='varid'>replicate</span> <span class='varid'>i</span> <span class='chr'>'#'</span><span class='layout'>)</span> <span class='varop'>++</span> <span class='varid'>s</span> <span class='varop'>++</span>
<span class='layout'>(</span><span class='varid'>replicate</span> <span class='layout'>(</span><span class='varid'>k</span> <span class='comment'>-</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='varid'>i</span><span class='layout'>)</span> <span class='chr'>'#'</span><span class='layout'>)</span>
<span class='varid'>k</span> <span class='keyglyph'>=</span> <span class='num'>2</span> <span class='varop'>*</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='num'>1</span>
<span class='varid'>used</span> <span class='keyglyph'>=</span> <span class='varid'>not</span> <span class='varop'>.</span> <span class='varid'>all</span> <span class='layout'>(</span><span class='varop'>`elem`</span> <span class='str'>"#."</span><span class='layout'>)</span></pre>
<p>Getting the other diagonals is similar, but again brings too much repetition.</p>
<pre><span class='definition'>negdiags</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='varid'>reverse</span> <span class='varop'>.</span> <span class='varid'>filter</span> <span class='varid'>used</span> <span class='varop'>.</span> <span class='varid'>transpose</span> <span class='varop'>.</span> <span class='varid'>map</span> <span class='varid'>shear</span> <span class='varop'>.</span> <span class='varid'>zip</span> <span class='keyglyph'>[</span><span class='num'>0</span><span class='keyglyph'>..</span><span class='keyglyph'>]</span>
<span class='keyword'>where</span> <span class='varid'>shear</span> <span class='layout'>(</span><span class='varid'>i</span><span class='layout'>,</span><span class='varid'>s</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='varid'>replicate</span> <span class='layout'>(</span><span class='varid'>k</span> <span class='comment'>-</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='varid'>i</span><span class='layout'>)</span> <span class='chr'>'#'</span><span class='layout'>)</span> <span class='varop'>++</span> <span class='varid'>s</span> <span class='varop'>++</span>
<span class='layout'>(</span><span class='varid'>replicate</span> <span class='varid'>i</span> <span class='chr'>'#'</span><span class='layout'>)</span>
<span class='varid'>k</span> <span class='keyglyph'>=</span> <span class='num'>2</span> <span class='varop'>*</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='num'>1</span>
<span class='varid'>used</span> <span class='keyglyph'>=</span> <span class='varid'>not</span> <span class='varop'>.</span> <span class='varid'>all</span> <span class='layout'>(</span><span class='varop'>`elem`</span> <span class='str'>"#."</span><span class='layout'>)</span></pre>
<p>Having <tt>Board</tt> values to play with is trivial:</p>
<pre><span class='varop'>></span> <span class='definition'>board</span> <span class='keyglyph'>::</span> <span class='conid'>String</span> <span class='keyglyph'>-></span> <span class='conid'>Board</span>
<span class='varop'>></span> <span class='definition'>board</span> <span class='varid'>s</span> <span class='keyglyph'>=</span> <span class='conid'>Board</span> <span class='varop'>$</span> <span class='varid'>go</span> <span class='varid'>s</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>go</span> <span class='conid'>[]</span> <span class='keyglyph'>=</span> <span class='conid'>[]</span>
<span class='varop'>></span> <span class='varid'>go</span> <span class='varid'>xs</span> <span class='keyglyph'>=</span> <span class='keyword'>let</span> <span class='layout'>(</span><span class='varid'>a</span><span class='layout'>,</span><span class='varid'>bs</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>splitAt</span> <span class='varid'>size</span> <span class='varid'>xs</span>
<span class='varop'>></span> <span class='keyword'>in</span> <span class='varid'>a</span> <span class='conop'>:</span> <span class='varid'>go</span> <span class='varid'>bs</span>
</pre>
<p>It chops one long string into rows, but with Haskell's usually-awkward multiline strings, it's not so bad. For example</p>
<pre><span class='definition'>startBoard</span> <span class='keyglyph'>=</span>
<span class='str'>".b.b.b.b\
\b.b.b.b.\
\.b.b.b.b\
\ . . . .\
\. . . . \
\w.w.w.w.\
\.w.w.w.w\
\w.w.w.w."</span></pre>
<p>An early cut at <tt>blueMoves</tt> and reducing the repetition in the rules for moves was</p>
<pre><span class='definition'>blueMoves</span> <span class='keyglyph'>::</span> <span class='conid'>Board</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span>
<span class='definition'>blueMoves</span> <span class='layout'>(</span><span class='varid'>diagonals</span> <span class='keyglyph'>-></span> <span class='layout'>(</span><span class='varid'>p</span><span class='layout'>,</span><span class='varid'>n</span><span class='layout'>)</span><span class='layout'>)</span> <span class='keyglyph'>=</span>
<span class='varid'>sum</span> <span class='varop'>$</span> <span class='varid'>map</span> <span class='varid'>move</span> <span class='varop'>$</span> <span class='varid'>concatMap</span> <span class='varid'>tails</span> <span class='varop'>$</span> <span class='varid'>p</span> <span class='varop'>++</span> <span class='varid'>n</span>
<span class='keyword'>where</span> <span class='varid'>move</span> <span class='layout'>(</span> <span class='varid'>b</span> <span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>b</span> <span class='varop'>`elem`</span> <span class='str'>"Bb"</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varid'>move</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span><span class='chr'>'B'</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varid'>move</span> <span class='layout'>(</span><span class='chr'>'b'</span><span class='conop'>:</span> <span class='varid'>w</span> <span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>w</span> <span class='varop'>`elem`</span> <span class='str'>"Ww"</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varid'>move</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span> <span class='varid'>w</span> <span class='conop'>:</span><span class='chr'>'B'</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>w</span> <span class='varop'>`elem`</span> <span class='str'>"Ww"</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varid'>move</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='num'>0</span></pre>
<p>Sticking with the theme of repetition, <tt>whiteMoves</tt> is nearly identical with little breadcrumbs of differences. That was all good because I wanted to have a testsuite before I started refactoring.</p>
<pre><span class='definition'>tests</span> <span class='keyglyph'>::</span> <span class='conid'>Test</span>
<span class='definition'>tests</span> <span class='keyglyph'>=</span> <span class='varid'>test</span>
<span class='keyglyph'>[</span> <span class='varid'>assertEqual</span> <span class='str'>"white must have piece to move"</span>
<span class='num'>0</span> <span class='layout'>(</span><span class='varid'>nw</span> <span class='str'>".b.b.b.b\
\b.b.b.b.\
\.b.b.b.b\
\ . . . .\
\. . . . \
\ . . . .\
\. . . . \
\ . . . ."</span><span class='layout'>)</span>
<span class='keyglyph'>]</span>
<span class='keyword'>where</span> <span class='varid'>nw</span> <span class='keyglyph'>=</span> <span class='varid'>whiteMoves</span> <span class='varop'>.</span> <span class='varid'>board</span></pre>
<p>Not bad for a start, but each testcase will have a dual for the other side—way too much copy-and-paste.</p>
<pre>*Checkers> runTestTT tests
Loading package HUnit-1.2.2.1 ... linking ... done.
Cases: 1 Tried: 1 Errors: 0 Failures: 0
Counts {cases = 1, tried = 1, errors = 0, failures = 0}</pre>
<p>Whee!</p>
<p>To wring out the duplication in the code for each side's moves, I considered using <a href="http://www.haskell.org/haskellwiki/Template_Haskell">Template Haskell</a>—a cousin of Lisp macros for Haskell. I decided to push lexical closures as far as I could, and the result is below.</p>
<pre><span class='varop'>></span> <span class='definition'>blueMoves</span><span class='layout'>,</span> <span class='varid'>whiteMoves</span> <span class='keyglyph'>::</span> <span class='conid'>Board</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span>
<span class='varop'>></span> <span class='keyglyph'>[</span><span class='varid'>blueMoves</span><span class='layout'>,</span> <span class='varid'>whiteMoves</span><span class='keyglyph'>]</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='keyword'>let</span> <span class='varid'>blueOrder</span> <span class='keyglyph'>=</span> <span class='varid'>id</span> <span class='comment'>-- diagonals emerge in blue's perspective</span>
<span class='varop'>></span> <span class='varid'>whiteOrder</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='varid'>reverse</span>
<span class='varop'>></span> <span class='varid'>count</span> <span class='layout'>(</span><span class='varid'>direction</span><span class='layout'>,</span><span class='varid'>side</span><span class='layout'>)</span> <span class='layout'>(</span><span class='varid'>diagonals</span> <span class='keyglyph'>-></span> <span class='varid'>ds</span><span class='layout'>)</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='varid'>sum</span> <span class='varop'>$</span> <span class='varid'>map</span> <span class='varid'>sideCanMove</span> <span class='varop'>$</span> <span class='varid'>concatMap</span> <span class='varid'>tails</span> <span class='varop'>$</span> <span class='varid'>direction</span> <span class='varop'>$</span> <span class='varid'>ds</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>sideCanMove</span> <span class='layout'>(</span> <span class='varid'>p</span> <span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>same</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='varid'>sideCanMove</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span> <span class='varid'>k</span> <span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>king</span> <span class='varid'>k</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='varid'>sideCanMove</span> <span class='layout'>(</span> <span class='varid'>p</span> <span class='conop'>:</span> <span class='varid'>o</span> <span class='conop'>:</span><span class='chr'>' '</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>same</span> <span class='varid'>p</span> <span class='varop'>&&</span> <span class='varid'>opponent</span> <span class='varid'>o</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='varid'>sideCanMove</span> <span class='layout'>(</span><span class='chr'>' '</span><span class='conop'>:</span> <span class='varid'>o</span> <span class='conop'>:</span> <span class='varid'>k</span> <span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>king</span> <span class='varid'>k</span> <span class='varop'>&&</span> <span class='varid'>opponent</span> <span class='varid'>o</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='varid'>sideCanMove</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='num'>0</span>
<span class='varop'>></span> <span class='varid'>same</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='varid'>piece</span> <span class='varid'>p</span> <span class='varop'>&&</span> <span class='varid'>toLower</span> <span class='varid'>p</span> <span class='varop'>==</span> <span class='varid'>toLower</span> <span class='varid'>side</span>
<span class='varop'>></span> <span class='varid'>opponent</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='varid'>piece</span> <span class='varid'>p</span> <span class='varop'>&&</span> <span class='varid'>toLower</span> <span class='varid'>p</span> <span class='varop'>/=</span> <span class='varid'>toLower</span> <span class='varid'>side</span>
<span class='varop'>></span> <span class='varid'>king</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='varid'>same</span> <span class='varid'>p</span> <span class='varop'>&&</span> <span class='varid'>p</span> <span class='varop'>==</span> <span class='varid'>toUpper</span> <span class='varid'>side</span>
<span class='varop'>></span> <span class='varid'>piece</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='varid'>p</span> <span class='varop'>`elem`</span> <span class='str'>"BbWw"</span> <span class='comment'>-- filter empty spaces</span>
<span class='varop'>></span> <span class='keyword'>in</span> <span class='varid'>map</span> <span class='varid'>count</span> <span class='keyglyph'>[</span> <span class='layout'>(</span><span class='varid'>blueOrder</span><span class='layout'>,</span> <span class='chr'>'b'</span><span class='layout'>)</span><span class='layout'>,</span> <span class='layout'>(</span><span class='varid'>whiteOrder</span><span class='layout'>,</span> <span class='chr'>'w'</span><span class='layout'>)</span> <span class='keyglyph'>]</span>
</pre>
<p>The code in <tt>count</tt> (notice the <a href="http://hackage.haskell.org/trac/ghc/wiki/ViewPatterns">view pattern</a>?) is a skeleton to be customized for the blue side and the white side, and it distills the repeated code. The definition of <tt>sideCanMove</tt> generalizes the rules for legal moves on either side. We have to reverse the diagonals to make them usable on the white side.</p>
<p>To get both sets of diagonals, the only difference is how to shear the board: bottom-away for positive slopes and top-away for negative.</p>
<pre><span class='varop'>></span> <span class='comment'>-- positive slopes slice from NW to SE</span>
<span class='varop'>></span> <span class='comment'>-- negative slopes slice from SW to NE</span>
<span class='varop'>></span> <span class='comment'>-- both extend in blue's direction (north-to-south)</span>
<span class='varop'>></span> <span class='definition'>diagonals</span> <span class='keyglyph'>::</span> <span class='conid'>Board</span> <span class='keyglyph'>-></span> <span class='keyglyph'>[</span><span class='conid'>String</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='definition'>diagonals</span> <span class='layout'>(</span><span class='conid'>Board</span> <span class='varid'>rows</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>positiveSlopes</span> <span class='varid'>rows</span> <span class='varop'>++</span> <span class='varid'>negativeSlopes</span> <span class='varid'>rows</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>positiveSlopes</span> <span class='keyglyph'>=</span> <span class='varid'>go</span> <span class='varop'>$</span> <span class='keyglyph'>\</span><span class='layout'>(</span><span class='varid'>i</span><span class='layout'>,</span><span class='varid'>xs</span><span class='layout'>)</span> <span class='keyglyph'>-></span> <span class='layout'>(</span><span class='varid'>i</span><span class='layout'>,</span> <span class='varid'>k</span> <span class='comment'>-</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='varid'>i</span><span class='layout'>,</span> <span class='varid'>xs</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>negativeSlopes</span> <span class='keyglyph'>=</span> <span class='varid'>go</span> <span class='varop'>$</span> <span class='keyglyph'>\</span><span class='layout'>(</span><span class='varid'>i</span><span class='layout'>,</span><span class='varid'>xs</span><span class='layout'>)</span> <span class='keyglyph'>-></span> <span class='layout'>(</span><span class='varid'>k</span> <span class='comment'>-</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='varid'>i</span><span class='layout'>,</span> <span class='varid'>i</span><span class='layout'>,</span> <span class='varid'>xs</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>k</span> <span class='keyglyph'>=</span> <span class='num'>2</span> <span class='varop'>*</span> <span class='varid'>size</span> <span class='comment'>-</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='varid'>used</span> <span class='keyglyph'>=</span> <span class='varid'>not</span> <span class='varop'>.</span> <span class='varid'>all</span> <span class='varid'>ignored</span>
<span class='varop'>></span> <span class='varid'>go</span> <span class='varid'>order</span> <span class='keyglyph'>=</span> <span class='varid'>filter</span> <span class='layout'>(</span><span class='varid'>not</span> <span class='varop'>.</span> <span class='varid'>null</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varop'>.</span> <span class='varid'>map</span> <span class='layout'>(</span><span class='varid'>filter</span> <span class='varop'>$</span> <span class='varid'>not</span> <span class='varop'>.</span> <span class='varid'>ignored</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varop'>.</span> <span class='varid'>transpose</span>
<span class='varop'>></span> <span class='varop'>.</span> <span class='varid'>map</span> <span class='layout'>(</span><span class='varid'>shear</span> <span class='varop'>.</span> <span class='varid'>order</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varop'>.</span> <span class='varid'>zip</span> <span class='keyglyph'>[</span><span class='num'>0</span><span class='keyglyph'>..</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>ignored</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='varop'>`elem`</span> <span class='str'>"#."</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>shear</span> <span class='layout'>(</span><span class='varid'>l</span><span class='layout'>,</span><span class='varid'>r</span><span class='layout'>,</span><span class='varid'>s</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='varid'>replicate</span> <span class='varid'>l</span> <span class='chr'>'#'</span><span class='layout'>)</span> <span class='varop'>++</span> <span class='varid'>s</span> <span class='varop'>++</span> <span class='layout'>(</span><span class='varid'>replicate</span> <span class='varid'>r</span> <span class='chr'>'#'</span><span class='layout'>)</span>
</pre>
<p>Finally come the tests that I added as I went. To factor out duplication, each board becomes two testcases. The first is as-is, and the same condition should hold for the other side. See the definition of <tt>invert</tt> in the <tt>where</tt> clause.</p>
<p>I had hoped for a more elegant result, but it was an interesting exercise and a fun problem!</p>
<pre><span class='varop'>></span> <span class='definition'>tests</span> <span class='keyglyph'>::</span> <span class='conid'>Test</span>
<span class='varop'>></span> <span class='definition'>tests</span> <span class='keyglyph'>=</span> <span class='varid'>test</span> <span class='varop'>$</span> <span class='varid'>concat</span>
<span class='varop'>></span> <span class='keyglyph'>[</span> <span class='varid'>checkMoves</span> <span class='str'>"must have piece to move"</span>
<span class='varop'>></span> <span class='num'>0</span> <span class='str'>"</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>one</span> <span class='varid'>move</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='varid'>w</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>one</span> <span class='varid'>king</span> <span class='varid'>move</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='conid'>W</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>two</span> <span class='varid'>moves</span><span class='str'>"
> 2 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span><span class='varid'>w</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>king</span> <span class='varid'>can</span> <span class='varid'>move</span> <span class='varid'>back</span> <span class='varid'>from</span> <span class='varid'>end</span><span class='str'>"
> 2 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='conid'>W</span><span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>can</span> <span class='varid'>jump</span> <span class='varid'>opponent</span> <span class='varid'>pawn</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span><span class='varid'>b</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='varid'>w</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>can't</span> <span class='varid'>jump</span> <span class='varid'>blocked</span> <span class='varid'>opponent</span><span class='str'>"
> 0 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span><span class='varid'>b</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='varid'>w</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>can</span> <span class='varid'>jump</span> <span class='varid'>opponent</span> <span class='varid'>king</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span><span class='conid'>B</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span><span class='varid'>w</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>king</span> <span class='varid'>can</span> <span class='varid'>jump</span> <span class='varid'>trailing</span> <span class='varid'>opponent</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='conid'>W</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>king</span> <span class='varid'>can't</span> <span class='varid'>jump</span> <span class='varid'>protected</span> <span class='varid'>opponent</span><span class='str'>"
> 0 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='conid'>W</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>king</span> <span class='varid'>can't</span> <span class='varid'>jump</span> <span class='varid'>onto</span> <span class='varid'>own</span> <span class='varid'>piece</span><span class='str'>"
> 1 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='conid'>W</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>w</span><span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>king</span> <span class='varid'>has</span> <span class='varid'>four</span> <span class='varid'>moves</span><span class='str'>"
> 4 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='conid'>W</span><span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> , checkMoves "</span><span class='varid'>cannot</span> <span class='varid'>displace</span> <span class='varid'>opponent</span> <span class='varid'>on</span> <span class='varid'>king</span> <span class='varid'>row</span><span class='str'>"
> 0 "</span><span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>b</span><span class='varop'>.</span><span class='varid'>b</span><span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='varid'>w</span><span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.\</span>
<span class='varop'>></span> <span class='varop'>\.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='keyglyph'>\</span>
<span class='varop'>></span> <span class='keyglyph'>\</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span> <span class='varop'>.</span><span class='str'>"
> ]
> where nw = whiteMoves . board
> nb = blueMoves . board
> checkMoves name expect b =
> [ assertEqual ("</span><span class='varid'>white</span><span class='conop'>:</span> <span class='str'>" ++ name) expect (nw b)
> , assertEqual ("</span><span class='varid'>blue</span><span class='conop'>:</span> <span class='str'>"</span> <span class='varop'>++</span> <span class='varid'>name</span><span class='layout'>)</span> <span class='varid'>expect</span> <span class='layout'>(</span><span class='varid'>nb</span> <span class='varop'>$</span> <span class='varid'>invert</span> <span class='varid'>b</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>invert</span> <span class='keyglyph'>=</span> <span class='varid'>reverse</span> <span class='varop'>.</span> <span class='varid'>replace</span> <span class='keyglyph'>[</span><span class='layout'>(</span><span class='chr'>'W'</span><span class='layout'>,</span><span class='chr'>'B'</span><span class='layout'>)</span><span class='layout'>,</span> <span class='layout'>(</span><span class='chr'>'w'</span><span class='layout'>,</span><span class='chr'>'b'</span><span class='layout'>)</span><span class='layout'>,</span> <span class='layout'>(</span><span class='chr'>'B'</span><span class='layout'>,</span><span class='chr'>'W'</span><span class='layout'>)</span><span class='layout'>,</span> <span class='layout'>(</span><span class='chr'>'b'</span><span class='layout'>,</span><span class='chr'>'w'</span><span class='layout'>)</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>replace</span> <span class='varid'>tbl</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='layout'>(</span><span class='keyglyph'>\</span><span class='varid'>c</span> <span class='keyglyph'>-></span> <span class='varid'>maybe</span> <span class='varid'>c</span> <span class='varid'>id</span> <span class='varop'>$</span> <span class='varid'>lookup</span> <span class='varid'>c</span> <span class='varid'>tbl</span><span class='layout'>)</span>
</pre>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-40031006239127840882010-10-18T08:04:00.003-05:002010-10-18T08:17:31.296-05:00Healthy weight loss diet the CrossFit wayThe CrossFit Journal published an easy guide to starting the Zone diet, and it's <a href="http://journal.crossfit.com/2004/05/zone-meal-plans-crossfit-journ.tpl">available as a free download</a>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigXt76kkTkMoVFyV2hEQNF86jgQfjAn06ISDxz81g9Uyy-QqEOTUm66zsJilZzRUe7FKf9XslCWAWf1mreVOcEyv5ePXubjX_Zr881NYyfVXmha0qQxz6_uKb-Q_ph7LGItgM_iA/s1600/IMG00121.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigXt76kkTkMoVFyV2hEQNF86jgQfjAn06ISDxz81g9Uyy-QqEOTUm66zsJilZzRUe7FKf9XslCWAWf1mreVOcEyv5ePXubjX_Zr881NYyfVXmha0qQxz6_uKb-Q_ph7LGItgM_iA/s320/IMG00121.jpg" width="320" /></a></div>
Check the chart on page 2 to find how many blocks per day you should eat. You could also tinker with this <a href="http://www.dbhonline.com/zoneful/p_calculator.htm">Zone block calculator</a>. You'll need to know your weight and have an idea of your body-fat percentage. The recommended activity level is 0.7 for Crossfitters, so select “Light to medium 2-3x per week.” Yes, I share your likely indignation at that unjust description!<br />
<br />
Page 3 gives a block chart with columns for proteins, carbs, and fats—plus a small combo section. The next page lists unfavorable carbs that earn this designation due to their tendency to rapidly spike your insulin (also known as having a high glycemic load). This doesn't mean you can't have them—you can Zone just about anything—but that you want to limit how often you eat them. Being from 2004, the table is a bit dated, and the Dr. Sears people have since promoted carrots to favorable status, for example. I'm not aware of other changes.<br />
<br />
<div style="margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px;">
The inset picture is a cellphone snapshot of my 4-block breakfast: 4 eggs scrambled in 1⅓ teaspoons of butter, an orange, half a cup of salsa, and a cucumber.</div>
<br />
I keep a copy of the block charts above my refrigerator at home. To put together a meal with the chart, you need to know how large it will be, <i>i.e.</i>, how many blocks, and then you pick that many blocks of protein, carbs, and fat. The chart on page 2 suggests five 2-block meals for a ten-block day, for example, but size your meals in a way that works best for you: maybe three 3-block meals and then a 1-block snack before bed.<br />
<br />
Let's walk through my thought process for today's 4-block “first lunch.” I wanted chicken breast, and the chart tells me an ounce is one block. That means I get four ounces of chicken breast. I like pears, and a pear counts for two blocks, leaving me with two more to go. A half-cup of carrots is a block, so a whole cup makes two blocks. For fat, about three pistachios constitute a block, so I had 12 (= 4 blocks × 3 pistachios/block). In summary,<br />
<ul>
<li>Protein: 4 ounces of chicken breast (4 blocks)</li>
<li>Carb: a pear (2 blocks); 1 c. carrots (2 blocks)</li>
<li>Fat: 12 pistachios (4 blocks)</li>
</ul>
After doing it a while, you'll memorize your frequent choices, and I put together the above meal without having to consult the chart. Pistachios aren't listed, so I must have looked it up on the web. For other examples (with pictures!), read Jeff's <a href="http://crossfitimpulse.com/the-zone-diet-explained-edited/">“The Zone Diet Explained”</a> blog post. For tips on eating out, read <a href="http://crossfitimpulse.com/top-10-zone-friendly-meals-in-huntsville-alabama/">“Top 10 Zone-Friendly Meals in Huntsville.”</a><br />
<br />
If you'd like a more exciting meal, the number of ingredients is entirely up to you. Remember that you don't necessarily have to use whole-block portions, so you could make a salad with several different ingredients. Just be sure that the totals add up correctly. The rest of the article has tasty and easy recipes, separated into 2-, 3-, 4-, and 5-block meals and also 1-block snacks. The chili is delicious!<br />
<br />
It does take a week or two of getting used to. Some suggest that many of our food cravings are due to hormonal imbalance, and Zone is designed to level them out. I no longer have the ups and downs from spiking my blood sugar with carb overload, and I'm leaner than I've been in 10+ years. Don't go crazy either: let yourself cheat now and then. Among many other benefits, fish oil will cut you some slack on your diet. A common recommendation is to start off eating strictly for a month and then, after seeing the great results this will produce, maintaining on an 80/20 cycle—strict during the week and relaxed on the weekends.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com2tag:blogger.com,1999:blog-16846333.post-79760382091389224812010-06-24T09:10:00.001-05:002010-06-24T09:12:05.836-05:00Hard-boiled eggs in a microwaveI found instructions at eHow for <a href="http://http://www.ehow.com/how_2247645_hardboil-eggs-microwave.html">making hard-boiled eggs in a microwave</a>. I tried it this morning, and it worked!
<p>
The tl;dr version of the steps is
<ol>
<li>fill bowl with enough water to cover eggs
<li>remove eggs
<li>bring water to a boil
<li>carefully place eggs in hot water
<li>cover with a plate and cook on low power for 8 minutes
<li>let stand for another 6-8 minutes
</ol>
<p>
I cooked the eggs in a GE Profile JES2251SJ microwave. I unintentionally left out the salt and vinegar. I cooked four eggs, and it took the water about 4 minutes to come to the initial boil. This particular model has power settings from 1 to 10, and I used setting 2 on the fifth step. The instructions say the plate is for limiting the mess in case an egg explodes, but I used an upside-down paper plate. I doubt it would have been great for containment.
<p>
After all this, I poured out the hot water and ran cold water over the eggs a couple of times. Then I added ice and waited a few minutes for them to cool off.
<p>
At this point, I was relieved that none of the eggs had exploded, but—as you might imagine—I was worried that I hadn't cooked them enough. I picked up the first, and it felt pretty solid. Then a gentle tap-tap-tap. No runny mess!
<p>
The yolks were well done, but the whites were a touch runny in places on the outside. Next time, I'll either try a slightly less-low low-power setting or let the eggs stand a bit longer.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-61176401189298971232010-05-13T22:08:00.000-05:002010-05-13T22:08:41.821-05:00Intel WiFi 6000 on Ubuntu 10.04A fresh install of Ubuntu 10.04 on a Dell Studio XPS 16 didn't want to enable its Intel Wireless WiFi Link 6000. Pressing the wifi touchkey didn't help.
<p>
Running <code>rfkill list</code> gave
<pre>0: phy0: Wireless LAN
Soft blocked: yes
Hard blocked: no</pre>
NetworkManager Applet reported wireless as disabled or device not ready.
<p>
I read that removing the <code>dell_laptop</code> kernel module might help, but it did no good in my case.
<p>
What finally did the trick for me was
<pre>sudo rfkill unblock wifi</pre>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com3tag:blogger.com,1999:blog-16846333.post-69440326499357349302010-03-01T14:31:00.004-06:002010-03-01T14:55:24.143-06:00Perl: conditional use and scope<p>A reader asks</p>
<blockquote><p>If I conditionally load a perl module, do those module variables get passed to the whole perl script.</p>
<pre>
if ( some_test ) {
use "perlmodule_001";
}
else {
use "perlmodule_002";
}
</pre>
Are the elements of either perl module available outside the <code>if</code> statement?
</blockquote>
<p>The main program from the question has a syntax error:</p>
<pre>syntax error at prog0 line 2, near "use "perlmodule_001""</pre>
<p>Perl's <a href="http://perldoc.perl.org/functions/use.html">documentation for <code>use</code></a> explains:</p>
<blockquote>
<p><code><b>use Module</b></code></p>
<p>Imports some semantics into the current package from the named module, generally by aliasing certain subroutine or variable names into your package. It is exactly equivalent to
<blockquote><pre>BEGIN { require Module; Module->import( LIST ); }</pre></blockquote>
except that Module <i>must</i> be a bareword.
</blockquote>
<p>Note the bareword constraint at the end: the compiler doesn't like the double quotes around the argument to <code>use</code>. Our friend was likely thinking of the older <a href="http://perldoc.perl.org/functions/require.html"><code>require</code></a> operator that <em>does</em> accept strings and arbitrary expressions in general.</p>
<p>Say we have two modules with alternative definitions of <code>$Foo</code> and <code>$Bar</code>:</p>
<blockquote><font face="monospace">
<font color="#a52a2a"><b>package</b></font><font color="#2e8b57"><b> Perlmodule_001;</b></font><br>
<br>
<font color="#a52a2a"><b>use </b></font>Exporter <font color="#ff00ff">'</font><font color="#ff00ff">import</font><font color="#ff00ff">'</font>;<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">@EXPORT</font> = <font color="#ff00ff">qw/</font><font color="#ff00ff"> $Foo $Bar </font><font color="#ff00ff">/</font>;<br>
<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">$Foo</font> = <font color="#ff00ff">"</font><font color="#ff00ff">apple</font><font color="#ff00ff">"</font>;<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">$Bar</font> = <font color="#ff00ff">"</font><font color="#ff00ff">orange</font><font color="#ff00ff">"</font>;<br>
<br>
<font color="#ff00ff">1</font>;<br>
</font></blockquote>
<p>and</p>
<blockquote><font face="monospace">
<font color="#a52a2a"><b>package</b></font><font color="#2e8b57"><b> Perlmodule_002;</b></font><br>
<br>
<font color="#a52a2a"><b>use </b></font>Exporter <font color="#ff00ff">'</font><font color="#ff00ff">import</font><font color="#ff00ff">'</font>;<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">@EXPORT</font> = <font color="#ff00ff">qw/</font><font color="#ff00ff"> $Foo $Bar </font><font color="#ff00ff">/</font>;<br>
<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">$Foo</font> = <font color="#ff00ff">42</font>;<br>
<font color="#a52a2a"><b>our</b></font> <font color="#008b8b">$Bar</font> = <font color="#ff00ff">"</font><font color="#ff00ff">w00t!</font><font color="#ff00ff">"</font>;<br>
<br>
<font color="#ff00ff">1</font>;<br>
</font></blockquote>
<p>Note the use of <code>Perlmodule_001</code>, for example, rather than <code>perlmodule_001</code>: the <a href="http://perldoc.perl.org/perlmodlib.html">perlmodlib documentation</a> notes, “Perl informally reserves lowercase module names for 'pragma' modules like <a href="http://perldoc.perl.org/integer.html"><code>integer</code></a> and <a href="http://perldoc.perl.org/strict.html"><code>strict</code></a>.”</p>
<p>Consider the following simple driver:</p>
<blockquote><font face="monospace">
<font color="#a020f0">#! /usr/bin/perl</font><br>
<br>
<font color="#a52a2a"><b>use warnings</b></font>;<br>
<font color="#a52a2a"><b>use strict</b></font>;<br>
<br>
<font color="#a52a2a"><b>if</b></font> (<font color="#008b8b">@ARGV</font> && <font color="#008b8b">$ARGV</font>[<font color="#ff00ff">0</font>] <font color="#a52a2a"><b>eq</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">two</font><font color="#ff00ff">"</font>) {<br>
<font color="#a52a2a"><b>use </b></font>Perlmodule_002;<br>
}<br>
<font color="#a52a2a"><b>else</b></font> {<br>
<font color="#a52a2a"><b>use </b></font>Perlmodule_001;<br>
}<br>
<br>
<font color="#a52a2a"><b>sub</b></font><font color="#008b8b"> </font><font color="#008b8b">maybeUndef</font><font color="#008b8b"> </font>{<br>
<font color="#a52a2a"><b>defined</b></font> <font color="#008b8b">$_</font>[<font color="#ff00ff">0</font>] ? <font color="#008b8b">$_</font>[<font color="#ff00ff">0</font>] : <font color="#ff00ff">"</font><font color="#ff00ff"><undefined></font><font color="#ff00ff">"</font>;<br>
<font color="#0000ff"># got 5.10?</font><br>
<font color="#0000ff"># $_[0] // "<undefined>";</font><br>
}<br>
<br>
<font color="#a52a2a"><b>print</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">Foo = </font><font color="#ff00ff">"</font>, maybeUndef(<font color="#008b8b">$Foo</font>), <font color="#ff00ff">"</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>,<br>
<font color="#ff00ff">"</font><font color="#ff00ff">Bar = </font><font color="#ff00ff">"</font>, maybeUndef(<font color="#008b8b">$Bar</font>), <font color="#ff00ff">"</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>;<br>
</font></blockquote>
<p>It uses <code>maybeUndef</code> to explicitly show when a value is undefined and also to silence potential undefined-value warnings.</p>
<p>The program seems to run as intended</p>
<pre>$ ./prog1
Foo = apple
Bar = orange</pre>
<p>but the output is the same even when an argument of <code>two</code> is supplied on the command line!<p>
<pre>$ ./prog1 two
Foo = apple
Bar = orange</pre>
<p>The good news is that the imported variables are in scope for the rest of the program, as indicated in the above documentation for <code>use</code> (with emphasis added):</p>
<blockquote>Imports some semantics <b>into the current package</b> from the named module …</blockquote>
<p>To understand why we never see <code>Perlmodule_002</code>'s <code>$Foo</code> and <code>$Bar</code>, note that <code>use</code> “is exactly equivalent to” <code>require</code> at <a href="http://perldoc.perl.org/perlmod.html#BEGIN%2c-UNITCHECK%2c-CHECK%2c-INIT-and-END"><code>BEGIN</code></a> time, and the perlmod documentation explains exactly when that is (with added emphasis):</p>
<blockquote>A <code>BEGIN</code> code block is executed as soon as possible, that is, the moment it is completely defined, <i>even before the rest of the containing file (or string) is parsed</i>.</blockquote>
<p>So the compiler sees <code>use Perlmodule_002</code> and processes it. Then it sees <code>use Perlmodule_001</code> and processes it. When the compiler finishes digesting the rest of the code, it's time for the execution phase, when the <code>@ARGV</code> check finally takes place. As written, <code>Perlmodule_001</code> will always win!</p>
<p>Because ordinary modules affect the current package, <code>use</code>ing an ordinary module inside a conditional block is entirely misleading. I was careful to qualify the previous statement for ordinary modules because the effects of some pragmatic modules (<i>e.g.</i>, <code>strict</code> and <code>integer</code>—note the lowercase names!) are limited tightly to the enclosing block only.</p>
<p>The fix is to process <code>@ARGV</code> at <code>BEGIN</code> time and conditionalize the module imports with the equivalent <code>require</code> and <code>import</code>:</p>
<blockquote><font face="monospace">
<font color="#a020f0">#! /usr/bin/perl</font><br>
<br>
<font color="#a52a2a"><b>use warnings</b></font>;<br>
<font color="#a52a2a"><b>use strict</b></font>;<br>
<br>
<font color="#a020f0">BEGIN</font> {<br>
<font color="#a52a2a"><b>if</b></font> (<font color="#008b8b">@ARGV</font> && <font color="#008b8b">$ARGV</font>[<font color="#ff00ff">0</font>] <font color="#a52a2a"><b>eq</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">two</font><font color="#ff00ff">"</font>) {<br>
<font color="#a52a2a"><b>require</b></font> Perlmodule_002;<br>
Perlmodule_002-><font color="#a52a2a"><b>import</b></font>;<br>
}<br>
<font color="#a52a2a"><b>else</b></font> {<br>
<font color="#a52a2a"><b>require</b></font> Perlmodule_001;<br>
Perlmodule_001-><font color="#a52a2a"><b>import</b></font>;<br>
}<br>
}<br>
<br>
<font color="#a52a2a"><b>sub</b></font><font color="#008b8b"> </font><font color="#008b8b">maybeUndef</font><font color="#008b8b"> </font>{<br>
<font color="#a52a2a"><b>defined</b></font> <font color="#008b8b">$_</font>[<font color="#ff00ff">0</font>] ? <font color="#008b8b">$_</font>[<font color="#ff00ff">0</font>] : <font color="#ff00ff">"</font><font color="#ff00ff"><undefined></font><font color="#ff00ff">"</font>;<br>
<font color="#0000ff"># got 5.10?</font><br>
<font color="#0000ff"># $_[0] // "<undefined>";</font><br>
}<br>
<br>
<font color="#a52a2a"><b>print</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">Foo = </font><font color="#ff00ff">"</font>, maybeUndef(<font color="#008b8b">$Foo</font>), <font color="#ff00ff">"</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>,<br>
<font color="#ff00ff">"</font><font color="#ff00ff">Bar = </font><font color="#ff00ff">"</font>, maybeUndef(<font color="#008b8b">$Bar</font>), <font color="#ff00ff">"</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>;<br>
</font></blockquote>
<p>An alternative is protecting <code>use</code> with <a href="http://perldoc.perl.org/functions/eval.html"><code>eval</code></a> as in</p>
<blockquote><font face="monospace"><font color="#a020f0">BEGIN</font> {<br>
<font color="#a52a2a"><b>if</b></font> (<font color="#008b8b">@ARGV</font> && <font color="#008b8b">$ARGV</font>[<font color="#ff00ff">0</font>] <font color="#a52a2a"><b>eq</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">two</font><font color="#ff00ff">"</font>) {<br>
<font color="#a52a2a"><b>eval</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">use Perlmodule_002</font><font color="#ff00ff">"</font>;<br>
}<br>
<font color="#0000ff"># ...</font><br></font>
</blockquote>
<p>so a particular <code>use</code> runs only when control reaches its <code>eval</code> but is ignored otherwise. This is a safe, sensible use of <code>eval</code>.</p>
<p>Either way, the program now does what we expect!</p>
<pre>$ ./prog2
Foo = apple
Bar = orange
$ ./prog2 two
Foo = 42
Bar = w00t!</pre>
<p>You might wonder why the code has to be inside a <code>BEGIN</code> block after the <code>use</code>s are conditionalized. If you have the <code>strict</code> pragma enabled—and you should!—it wants variables to be imported and declared before execution begins. Otherwise, compilation will fail because for all it knows, <code>$Foo</code> and <code>$Bar</code> in the <code>main</code> package were typos.</p>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-29741709058236254252010-02-21T14:51:00.001-06:002010-02-21T14:52:25.041-06:00Haskell Platform on a fresh Ubuntu installWith newly-installed Ubuntu 9.10, I attempted to install version 2009.2.0.2 of the <a href="http://hackage.haskell.org/platform/">Haskell Platform</a>, but the build of <code>mtl</code> failed:
<pre>Could not find module `Control.Monad'</pre>
But <code>ghci</code> knew about <code>Control.Monad</code>!
<pre>Prelude> :m + Control.Monad
Prelude Control.Monad></pre>
Google searches yielded no relevant hits. I did find <a href="http://davidsiegel.org/haskell-platform-in-karmic-koala/">Installing haskell-platform in Ubuntu 9.10 “Karmic Koala”</a> by David Siegel, where he mentions installing prerequisites:
<pre>sudo apt-get install ghc6 ghc6-prof ghc6-doc haddock libglut-dev happy alex \
libedit-dev zlib1g-dev checkinstall</pre>
Even with these packages in place, the build continued to fail with the same error.
<p>
In an earlier iteration, I had installed <code>libghc6-mtl-dev</code> from <a href="http://ubuntu-tutorials.com/2007/01/04/package-management-with-apt-ubuntu-all-versions/">APT</a>, but after removing it, the <code>mtl</code> build succeeded along with the rest of the Haskell Platform!
<p>
The problem is the Haskell Platform build wants to install packages with and without profiling, but this means you also need profiling versions of all the prerequisite Haskell packages. (Note the presence of <code>ghc6-prof</code> in the above <code>apt-get</code> command.)
<p>
Cabal could have saved me lots of headscratching by telling me in its error message that it couldn't find a <em>profiling</em> version of <code>Control.Monad</code>!Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-39026408027907703212010-02-19T14:46:00.002-06:002010-02-19T14:56:56.469-06:00Reading variable-length lines from a text file in CSuppose for each line of some text file you want to read the entire line into a buffer and do some processing on it.
<p>
A common approach is to choose a fixed maximum length and hope for the best with <a href="http://en.wikipedia.org/wiki/Fgets">fgets</a>, but such a program breaks if any line's length is greater than this arbitrary limit.
<p>
The program below handles all the edge cases concomitant with fgets:
<p>
<font face="monospace">
<font color="#a020f0">#include </font><font color="#ff00ff"><errno.h></font><br>
<font color="#a020f0">#include </font><font color="#ff00ff"><stdio.h></font><br>
<font color="#a020f0">#include </font><font color="#ff00ff"><stdlib.h></font><br>
<font color="#a020f0">#include </font><font color="#ff00ff"><string.h></font><br>
<br>
<font color="#0000ff">/*</font><font color="#0000ff"> argv[0], potentially used in error messages </font><font color="#0000ff">*/</font><br>
<font color="#2e8b57"><b>const</b></font> <font color="#2e8b57"><b>char</b></font> *progname;<br>
<br>
<font color="#2e8b57"><b>typedef</b></font> <font color="#2e8b57"><b>void</b></font> (*processor)(<font color="#2e8b57"><b>const</b></font> <font color="#2e8b57"><b>char</b></font> *s);<br>
<font color="#2e8b57"><b>int</b></font> for_each_line(<font color="#2e8b57"><b>const</b></font> <font color="#2e8b57"><b>char</b></font> *path, processor p);<br>
<br>
<font color="#0000ff">/*</font><font color="#0000ff"> simple processor that prints each line to the standard output </font><font color="#0000ff">*/</font><br>
<font color="#2e8b57"><b>void</b></font> print(<font color="#2e8b57"><b>const</b></font> <font color="#2e8b57"><b>char</b></font> *s)<br>
{<br>
printf(<font color="#ff00ff">"</font><font color="#6a5acd">%s</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, s);<br>
}<br>
<br>
<font color="#2e8b57"><b>int</b></font> main(<font color="#2e8b57"><b>int</b></font> argc, <font color="#2e8b57"><b>char</b></font> **argv)<br>
{<br>
progname = argv[<font color="#ff00ff">0</font>];<br>
<br>
<font color="#a52a2a"><b>if</b></font> (argc != <font color="#ff00ff">2</font>) {<br>
fprintf(<font color="#ff00ff">stderr</font>, <font color="#ff00ff">"Usage: </font><font color="#6a5acd">%s</font><font color="#ff00ff"> file</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, progname);<br>
<font color="#a52a2a"><b>return</b></font> <font color="#ff00ff">1</font>;<br>
}<br>
<br>
<font color="#a52a2a"><b>return</b></font> for_each_line(argv[<font color="#ff00ff">1</font>], print) ? <font color="#ff00ff">0</font> : <font color="#ff00ff">1</font>;<br>
}<br>
<br>
<font color="#2e8b57"><b>int</b></font> for_each_line(<font color="#2e8b57"><b>const</b></font> <font color="#2e8b57"><b>char</b></font> *path, processor p)<br>
{<br>
<font color="#2e8b57"><b>FILE</b></font> *f;<br>
<font color="#2e8b57"><b>char</b></font> *buf, *line;<br>
<font color="#2e8b57"><b>size_t</b></font> capacity = <font color="#ff00ff">80</font>; <font color="#0000ff">/*</font><font color="#0000ff"> reasonable guess at max length </font><font color="#0000ff">*/</font><br>
<font color="#2e8b57"><b>size_t</b></font> remaining = capacity;<br>
<font color="#2e8b57"><b>int</b></font> success = <font color="#ff00ff">1</font>;<br>
<br>
f = fopen(path, <font color="#ff00ff">"r"</font>);<br>
<font color="#a52a2a"><b>if</b></font> (!f) {<br>
fprintf(<font color="#ff00ff">stderr</font>, <font color="#ff00ff">"</font><font color="#6a5acd">%s</font><font color="#ff00ff">: open </font><font color="#6a5acd">%s</font><font color="#ff00ff">: </font><font color="#6a5acd">%s</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>,<br>
progname, path, strerror(errno));<br>
<font color="#a52a2a"><b>return</b></font> <font color="#ff00ff">0</font>;<br>
}<br>
<br>
line = malloc(capacity);<br>
<font color="#a52a2a"><b>if</b></font> (!line) {<br>
fprintf(<font color="#ff00ff">stderr</font>, <font color="#ff00ff">"</font><font color="#6a5acd">%s</font><font color="#ff00ff">: malloc: </font><font color="#6a5acd">%s</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, progname, strerror(errno));<br>
fclose(f);<br>
<font color="#a52a2a"><b>return</b></font> <font color="#ff00ff">0</font>;<br>
}<br>
<br>
<font color="#0000ff">/*</font><br>
<font color="#0000ff"> * On each iteration, read into buf the rest of a line whose length</font><br>
<font color="#0000ff"> * is at most remaining. We can be certain that we have the whole</font><br>
<font color="#0000ff"> * line only when the string contains '\n', in which case we</font><br>
<font color="#0000ff"> * remove the terminator and call the processor on the entire line.</font><br>
<font color="#0000ff"> *</font><br>
<font color="#0000ff"> * Otherwise, we double line's size and try again.</font><br>
<font color="#0000ff"> *</font><br>
<font color="#0000ff"> * It may seem tempting to also test feof(f) to check whether we</font><br>
<font color="#0000ff"> * have the whole line, but in the unlucky edge case where a file</font><br>
<font color="#0000ff"> * doesn't end with '\n' and its last line is exactly remaining-1</font><br>
<font color="#0000ff"> * in length, feof(f) will not yet be true, hence the possibility</font><br>
<font color="#0000ff"> * of printing the last line outside the loop.</font><br>
<font color="#0000ff"> </font><font color="#0000ff">*/</font><br>
buf = line;<br>
line[<font color="#ff00ff">0</font>] = <font color="#6a5acd">'\0'</font>;<br>
<font color="#a52a2a"><b>while</b></font> (fgets(buf, remaining, f)) {<br>
<font color="#2e8b57"><b>char</b></font> *eol = strchr(buf, <font color="#6a5acd">'\n'</font>);<br>
<font color="#a52a2a"><b>if</b></font> (eol) {<br>
*eol = <font color="#6a5acd">'\0'</font>;<br>
p(line);<br>
buf = line;<br>
remaining = capacity;<br>
line[<font color="#ff00ff">0</font>] = <font color="#6a5acd">'\0'</font>;<br>
}<br>
<font color="#a52a2a"><b>else</b></font> {<br>
<font color="#2e8b57"><b>size_t</b></font> used = buf + remaining - line;<br>
<br>
line = realloc(line, capacity * <font color="#ff00ff">2</font>);<br>
<font color="#a52a2a"><b>if</b></font> (!line) {<br>
fprintf(<font color="#ff00ff">stderr</font>, <font color="#ff00ff">"</font><font color="#6a5acd">%s</font><font color="#ff00ff">: realloc: </font><font color="#6a5acd">%s</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, progname, strerror(errno));<br>
fclose(f);<br>
<font color="#a52a2a"><b>return</b></font> <font color="#ff00ff">0</font>;<br>
}<br>
<br>
buf = line + used - <font color="#ff00ff">1</font>;<br>
capacity *= <font color="#ff00ff">2</font>;<br>
remaining = capacity - used;<br>
}<br>
}<br>
<br>
<font color="#a52a2a"><b>if</b></font> (errno) {<br>
fprintf(<font color="#ff00ff">stderr</font>, <font color="#ff00ff">"</font><font color="#6a5acd">%s</font><font color="#ff00ff">: fgets: </font><font color="#6a5acd">%s</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, progname, strerror(errno));<br>
success = <font color="#ff00ff">0</font>;<br>
}<br>
<font color="#a52a2a"><b>else</b></font> <font color="#a52a2a"><b>if</b></font> (line[<font color="#ff00ff">0</font>]) {<br>
<font color="#2e8b57"><b>char</b></font> *eol = strchr(buf, <font color="#6a5acd">'\n'</font>);<br>
<font color="#a52a2a"><b>if</b></font> (eol)<br>
*eol = <font color="#6a5acd">'\0'</font>;<br>
p(line);<br>
}<br>
<br>
fclose(f);<br>
free(line);<br>
<br>
<font color="#a52a2a"><b>return</b></font> success;<br>
}<br>
</font>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com1tag:blogger.com,1999:blog-16846333.post-33394445348603497522009-11-24T23:00:00.007-06:002009-11-24T23:40:36.773-06:00GMT crontabDealing with time is a problem domain where everything seems like it ought to be dead-simple, but getting all the fiddly details correct is never trivial.
<p>
Below is a sketch at converting simple <a href="http://en.wikipedia.org/wiki/Cron">crontabs</a> whose times are expressed in GMT to the host's local time. This blog post wishes it were a literate Haskell program.
<p>
In general, if you care about timezones, represent times internally in some universal format and convert times for display purposes only.
<p>
Front matter:
<p>
<font face="monospace">
<font color="#a020f0">#! /usr/bin/perl</font><br>
<br>
<font color="#804040">use warnings</font>;<br>
<font color="#804040">use strict</font>;<br>
<br>
<font color="#804040">use </font>feature <font color="#ff00ff">qw/</font><font color="#ff00ff"> switch </font><font color="#ff00ff">/</font>;<br>
<br>
<font color="#804040">use </font>Time::Local <font color="#ff00ff">qw/</font><font color="#ff00ff"> timegm </font><font color="#ff00ff">/</font>;<br>
</font>
<p>
Given a five-field job time in GMT, <tt>gmtoday</tt> returns the hour in the local timezone and the day offset. The function's name comes from its implementation, nearly always a terrible practice. It uses the time the program started (<a href="http://perldoc.perl.org/perlvar.html#%24BASETIME"><tt>$^T</tt></a>), decomposes it with <a href="http://perldoc.perl.org/functions/gmtime.html"><tt>gmtime</tt></a>, substitutes the hour from cron, and goes the other direction with <a href="http://perldoc.perl.org/Time/Local.html#timelocal()-and-timegm()"><tt>timegm</tt></a>.
<p>
Now that I think about it, this probably doesn't handle the day-of-week wraparound: Sunday is 0 and Saturday is 6, but the days are adjacent.
<p>
<font face="monospace">
<font color="#804040">sub</font><font color="#0000ff"> </font><font color="#0000ff">gmtoday</font><font color="#0000ff"> </font>{<br>
<font color="#804040">my</font>(<font color="#0000ff">$gmmin</font>,<font color="#0000ff">$gmhr</font>,<font color="#0000ff">$gmmday</font>,<font color="#0000ff">$gmmon</font>,<font color="#0000ff">$gmwday</font>) = <font color="#0000ff">@_</font>;<br>
<br>
<font color="#804040">my</font> <font color="#0000ff">@gmtime</font> = <font color="#804040">gmtime</font> <font color="#0000ff">$^T</font>;<br>
<font color="#804040">my</font>(<font color="#804040">undef</font>,<font color="#804040">undef</font>,<font color="#0000ff">$hour</font>,<font color="#0000ff">$mday</font>,<font color="#0000ff">$mon</font>,<font color="#0000ff">$year</font>,<font color="#0000ff">$wday</font>) = <font color="#0000ff">@gmtime</font>;<br>
<br>
<font color="#804040">my</font> <font color="#0000ff">@args</font> = (<br>
<font color="#ff00ff">0</font>, <font color="#ff0000"># sec</font><br>
<font color="#0000ff">$gmmin</font> <font color="#804040">eq</font> <font color="#ff00ff">"</font><font color="#ff00ff">*</font><font color="#ff00ff">"</font> ? <font color="#ff00ff">"</font><font color="#ff00ff">0</font><font color="#ff00ff">"</font> : <font color="#0000ff">$gmmin</font>,<br>
<font color="#0000ff">$gmhr</font>,<br>
<font color="#0000ff">$mday</font>, <br>
<font color="#0000ff">$mon</font>,<br>
<font color="#0000ff">$year</font>,<br>
);<br>
<br>
<font color="#804040">my</font>(<font color="#0000ff">$lhour</font>,<font color="#0000ff">$lwday</font>) = (<font color="#804040">localtime</font> timegm <font color="#0000ff">@args</font>)[<font color="#ff00ff">2</font>,<font color="#ff00ff">6</font>];<br>
<br>
(<font color="#0000ff">$lhour</font>, <font color="#0000ff">$lwday</font> - <font color="#0000ff">$wday</font>);<br>
}<br>
</font>
<p>
Given the five-field time specification from the current cronjob, <tt>localcron</tt> converts it from GMT to local time. Note that a fully general implementation would support 32 (i.e., <tt>2 ** 5</tt>) cases.
<p>
This is a nice use of <a href="http://perldoc.perl.org/perlsyn.html#Switch-statements"><tt>given-when</tt></a>, new in perl-5.10, and resembles a familiar shell idiom.
<p>
<font face="monospace">
<font color="#804040">sub</font><font color="#0000ff"> </font><font color="#0000ff">localcron</font><font color="#0000ff"> </font>{<br>
<font color="#804040">my</font>(<font color="#0000ff">$gmmin</font>,<font color="#0000ff">$gmhr</font>,<font color="#0000ff">$gmmday</font>,<font color="#0000ff">$gmmon</font>,<font color="#0000ff">$gmwday</font>) = <font color="#0000ff">@_</font>;<br>
<br>
given (<font color="#ff00ff">"</font><font color="#0000ff">$gmmin</font><font color="#ff00ff">,</font><font color="#0000ff">$gmhr</font><font color="#ff00ff">,</font><font color="#0000ff">$gmmday</font><font color="#ff00ff">,</font><font color="#0000ff">$gmmon</font><font color="#ff00ff">,</font><font color="#0000ff">$gmwday</font><font color="#ff00ff">"</font>) {<br>
<font color="#ff0000"># trivial case: no adjustment necessary</font><br>
when (<font color="#804040">/</font><font color="#ff00ff">^</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">$</font><font color="#804040">/</font>) {<br>
<font color="#804040">return</font> (<font color="#0000ff">$gmmin</font>,<font color="#0000ff">$gmhr</font>,<font color="#0000ff">$gmmday</font>,<font color="#0000ff">$gmmon</font>,<font color="#0000ff">$gmwday</font>);<br>
}<br>
<br>
<font color="#ff0000"># hour and maybe minute</font><br>
when (<font color="#804040">/</font><font color="#ff00ff">^</font><font color="#ff00ff">(</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">|</font><font color="#ff00ff">\*</font><font color="#ff00ff">)</font><font color="#ff00ff">,</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">$</font><font color="#804040">/</font>) {<br>
<font color="#804040">my</font>(<font color="#0000ff">$lhour</font>) = gmtoday <font color="#0000ff">@_</font>;<br>
<font color="#804040">return</font> (<font color="#0000ff">$gmmin</font>,<font color="#0000ff">$lhour</font>,<font color="#0000ff">$gmmday</font>,<font color="#0000ff">$gmmon</font>,<font color="#0000ff">$gmwday</font>);<br>
}<br>
<br>
<font color="#ff0000"># day of week, hour, and maybe minute</font><br>
when (<font color="#804040">/</font><font color="#ff00ff">^</font><font color="#ff00ff">(</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">|</font><font color="#ff00ff">\*</font><font color="#ff00ff">)</font><font color="#ff00ff">,</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\*</font><font color="#ff00ff">,</font><font color="#ff00ff">\d</font><font color="#ff00ff">+</font><font color="#ff00ff">$</font><font color="#804040">/</font>) {<br>
<font color="#804040">my</font>(<font color="#0000ff">$lhour</font>,<font color="#0000ff">$wdoff</font>) = gmtoday <font color="#0000ff">@_</font>;<br>
<font color="#804040">return</font> (<font color="#0000ff">$gmmin</font>,<font color="#0000ff">$lhour</font>,<font color="#0000ff">$gmmday</font>,<font color="#0000ff">$gmmon</font>,<font color="#0000ff">$gmwday</font>+<font color="#0000ff">$wdoff</font>);<br>
}<br>
<br>
default {<br>
<font color="#804040">warn</font> <font color="#ff00ff">"</font><font color="#0000ff">$0</font><font color="#ff00ff">: unhandled case: </font><font color="#0000ff">$gmmin</font><font color="#ff00ff"> </font><font color="#0000ff">$gmhr</font><font color="#ff00ff"> </font><font color="#0000ff">$gmmday</font><font color="#ff00ff"> </font><font color="#0000ff">$gmmon</font><font color="#ff00ff"> </font><font color="#0000ff">$gmwday</font><font color="#ff00ff">"</font>;<br>
<font color="#804040">return</font>;<br>
}<br>
}<br>
}<br>
</font>
<p>
Finally, the main loop reads each line from the input and generates the appropriate output. Note that we do not throw away unhandled times: they instead appear in the output as comments.
<p>
<font face="monospace">
<font color="#804040">while</font> (<>) {<br>
<font color="#804040">if</font> (<font color="#804040">/</font><font color="#ff00ff">^</font><font color="#ff00ff">\s</font><font color="#ff00ff">*(?:</font><font color="#ff00ff">#</font><font color="#ff00ff">.*)?</font><font color="#ff00ff">$</font><font color="#804040">/</font>) {<br>
<font color="#804040">print</font>;<br>
<font color="#804040">next</font>;<br>
}<br>
<br>
<font color="#804040">chomp</font>;<br>
<font color="#804040">my</font> <font color="#0000ff">@gmcron</font> = <font color="#804040">split</font> <font color="#ff00ff">"</font><font color="#ff00ff"> </font><font color="#ff00ff">"</font>, <font color="#0000ff">$_</font>, <font color="#ff00ff">6</font>;<br>
<br>
<font color="#804040">my</font> <font color="#0000ff">$cmd</font> = <font color="#804040">pop</font> <font color="#0000ff">@gmcron</font>;<br>
<font color="#804040">my</font> <font color="#0000ff">@localcron</font> = localcron <font color="#0000ff">@gmcron</font>;<br>
<br>
<font color="#804040">if</font> (<font color="#0000ff">@localcron</font>) {<br>
<font color="#804040">print</font> <font color="#804040">join</font>(<font color="#ff00ff">"</font><font color="#ff00ff"> </font><font color="#ff00ff">"</font> => <font color="#0000ff">@localcron</font>), <font color="#ff00ff">"</font><font color="#ff00ff">\t</font><font color="#ff00ff">"</font>, <font color="#0000ff">$cmd</font>, <font color="#ff00ff">"</font><font color="#ff00ff">\n</font><font color="#ff00ff">"</font><br>
}<br>
<font color="#804040">else</font> {<br>
<font color="#804040">print</font> <font color="#ff00ff">"</font><font color="#ff00ff"># </font><font color="#ff00ff">"</font>, <font color="#0000ff">$_</font>, <font color="#ff00ff">"</font><font color="#ff00ff">\n</font><font color="#ff00ff">"</font>;<br>
}<br>
}<br>
</font>
<p>
For this sorta-crontab
<pre>33 * * * * minute only
0 0 * * * minute and hour
0 10 * * 1 minute, hour, and wday (same day)
0 2 * * 1 minute, hour, and wday (cross day)</pre>
the output is the following when run in the US Central timezone:
<pre>33 * * * * minute only
0 18 * * * minute and hour
0 4 * * 1 minute, hour, and wday (same day)
0 20 * * 0 minute, hour, and wday (cross day)</pre>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com1tag:blogger.com,1999:blog-16846333.post-51049519752189950352009-11-22T08:12:00.004-06:002010-01-09T12:10:43.686-06:00Sweet potato casserole recipe<div>If you have any other recipes for this dish, throw them out. This is the last you'll ever need.</div><div>
</div>For everyone who's tired of having to set a good example for the kids and wait until after dinner to eat dessert, add this recipe to your Thanksgiving feast.<div>
</div><div><span class="Apple-style-span" style="font-family: sans-serif; font-size: 13px; line-height: 19px; "><p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em; "><b>Ingredients:</b></p><ul style="line-height: 1.5em; list-style-type: square; margin-top: 0.3em; margin-right: 0px; margin-bottom: 0px; margin-left: 1.5em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><li style="margin-bottom: 0.1em; ">3 cups cooked potatoes (about 4 medium potatoes)</li><li style="margin-bottom: 0.1em; ">2 eggs</li><li style="margin-bottom: 0.1em; ">¼ teaspoon salt</li><li style="margin-bottom: 0.1em; ">1 teaspoon vanilla</li><li style="margin-bottom: 0.1em; ">½ cup milk</li><li style="margin-bottom: 0.1em; ">¼ cup butter</li><li style="margin-bottom: 0.1em; ">1 cup sugar</li></ul><p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em; "><b>Directions</b></p><p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em; ">Blend all ingredients with mixer and pour into casserole dish. Combine dry topping ingredients and then add melted butter. Mix until crumbly and sprinkle over potato mixture. Bake at 350° for 30 minutes.</p><p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em; "><b>Topping:</b></p><ul style="line-height: 1.5em; list-style-type: square; margin-top: 0.3em; margin-right: 0px; margin-bottom: 0px; margin-left: 1.5em; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; "><li style="margin-bottom: 0.1em; ">1 cup brown sugar</li><li style="margin-bottom: 0.1em; ">¼ cup flour (all-purpose)</li><li style="margin-bottom: 0.1em; ">¼ cup butter</li><li style="margin-bottom: 0.1em; ">1 cup chopped pecans</li></ul><p style="margin-top: 0.4em; margin-right: 0px; margin-bottom: 0.5em; margin-left: 0px; line-height: 1.5em; "><i>From Hazel Green Elementary School cookbook with modifications by Samantha Bacon.</i></p></span></div>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-9601229498149025122009-10-22T13:03:00.005-05:002009-10-22T13:24:59.391-05:00While you're wondering<div>Hey Vols, this weekend while a delightful little tune is being sung in your honor, the more curious among your number may want to know just what a <a href="http://en.wikipedia.org/wiki/Yellowhammer">yellowhammer</a> is. See for yourselves:</div><div>
</div><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYfGBu-rAUE9wRxjVehDxdjXXPVLeko5FnRHEmDggn-7HP1mBDCBJYVlvbVgibmn7MC81ZAgNLX9b0IC_J1uX6T9H5Vt1Of2DnpwOfTgiFTndt_nK05aV18thWnOr1Ra2ZddXFWQ/s1600-h/yellowhammer-half.jpg"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 267px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYfGBu-rAUE9wRxjVehDxdjXXPVLeko5FnRHEmDggn-7HP1mBDCBJYVlvbVgibmn7MC81ZAgNLX9b0IC_J1uX6T9H5Vt1Of2DnpwOfTgiFTndt_nK05aV18thWnOr1Ra2ZddXFWQ/s400/yellowhammer-half.jpg" border="0" alt="" id="BLOGGER_PHOTO_ID_5395487338011431938" /></a><div style="text-align: center;"><span class="Apple-style-span" style="font-size:x-small;">Image credit: </span><a href="http://news.bbc.co.uk/2/shared/spl/hi/pop_ups/08/sci_nat_enl_1256134835/html/1.stm"><span class="Apple-style-span" style="font-size:x-small;">BBC</span></a></div><div>
</div><div>The yellowhammer has been the state bird of Alabama since 1927. <a href="http://www.archives.state.al.us/Emblems/St_bird.html">According to the Alabama Department of Archives & History</a>,</div><div><span class="Apple-style-span" style=" -webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px;"><blockquote>Alabama has been known as the “Yellowhammer State” since the Civil War. The yellowhammer nickname was applied to the Confederate soldiers from Alabama when a company of young cavalry soldiers from Huntsville, under the command of Rev. D.C. Kelly, arrived at Hopkinsville, KY, where Gen. Forrest's troops were stationed. The officers and men of the Huntsville company wore fine, new uniforms, whereas the soldiers who had long been on the battlefields were dressed in faded, worn uniforms. On the sleeves, collars and coattails of the new calvary troop were bits of brilliant yellow cloth. As the company rode past Company A, Will Arnett cried out in greeting “Yellowhammer, Yellowhammer, flicker, flicker!” The greeting brought a roar of laughter from the men and from that moment the Huntsville soldiers were spoken of as the “yellowhammer company.” The term quickly spread throughout the Confederate Army and all Alabama troops were referred to unofficially as the “Yellowhammers.”</blockquote></span></div>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com2tag:blogger.com,1999:blog-16846333.post-12359568486434291752009-09-19T13:06:00.005-05:002009-09-19T23:33:38.054-05:00Haskell crapsA Haskell neophyte at <code>$WORK</code> talked about writing a <a href="http://en.wikipedia.org/wiki/Craps">craps</a> simulator as a learning exercise. The <a href="http://en.wikipedia.org/wiki/Craps#The_rules_of_play_against_a_bank_or_casino">rules</a>, limiting consideration to pass-line bets, are complex enough to make it an interesting <a href="http://codekata.pragprog.com/2007/01/code_kata_backg.html">kata</a>. Designing a processor for the game's complex prop bets, on the other hand, might make a good interview discussion.
<p>
Front matter:
<pre><span class='varop'>></span> <span class='keyword'>module</span> <span class='conid'>Craps</span> <span class='layout'>(</span> <span class='varid'>games</span>
<span class='varop'>></span> <span class='layout'>,</span> <span class='varid'>rolls</span>
<span class='varop'>></span> <span class='layout'>,</span> <span class='varid'>runTests</span>
<span class='varop'>></span> <span class='layout'>,</span> <span class='conid'>Game</span>
<span class='varop'>></span> <span class='layout'>,</span> <span class='conid'>Roll</span>
<span class='varop'>></span> <span class='layout'>)</span> <span class='keyword'>where</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Data</span><span class='varop'>.</span><span class='conid'>List</span> <span class='layout'>(</span><span class='layout'>(</span><span class='varop'>\\</span><span class='layout'>)</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>System</span><span class='varop'>.</span><span class='conid'>Random</span> <span class='layout'>(</span><span class='varid'>randomRs</span><span class='layout'>,</span><span class='conid'>Random</span><span class='layout'>,</span><span class='conid'>RandomGen</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Test</span><span class='varop'>.</span><span class='conid'>QuickCheck</span> <span class='layout'>(</span><span class='varid'>choose</span><span class='layout'>,</span><span class='varid'>forAll</span><span class='layout'>,</span><span class='varid'>oneof</span><span class='layout'>,</span><span class='varid'>sized</span><span class='layout'>,</span><span class='conid'>Arbitrary</span><span class='layout'>(</span><span class='keyglyph'>..</span><span class='layout'>)</span><span class='layout'>,</span><span class='conid'>Gen</span><span class='layout'>,</span><span class='conid'>Property</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='conid'>Test</span><span class='varop'>.</span><span class='conid'>QuickCheck</span><span class='varop'>.</span><span class='conid'>Batch</span> <span class='layout'>(</span><span class='varid'>defOpt</span><span class='layout'>,</span><span class='varid'>run</span><span class='layout'>,</span><span class='conid'>TestOptions</span><span class='layout'>(</span><span class='keyglyph'>..</span><span class='layout'>)</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>import</span> <span class='keyword'>qualified</span> <span class='conid'>Test</span><span class='varop'>.</span><span class='conid'>QuickCheck</span><span class='varop'>.</span><span class='conid'>Batch</span> <span class='keyword'>as</span> <span class='conid'>QC</span>
</pre>
Craps is played with two dice:
<pre>
<span class='varop'>></span> <span class='keyword'>data</span> <span class='conid'>Roll</span> <span class='keyglyph'>=</span> <span class='conid'>Roll</span> <span class='conid'>Int</span> <span class='conid'>Int</span>
<span class='varop'>></span> <span class='keyword'>deriving</span> <span class='layout'>(</span><span class='conid'>Show</span><span class='layout'>)</span>
</pre>
At the pass line, the bettor can win two ways and lose two ways. With no point, rolls of 7 or 11 win (“natural”), and rolls of 2, 3, or 12 lose (“craps”). Any other roll becomes the point, and the shooter continues until she rolls the point again (“pass” or “win”) or 7 (“seven out”).
<pre>
<span class='varop'>></span> <span class='keyword'>data</span> <span class='conid'>Game</span> <span class='keyglyph'>=</span> <span class='conid'>Natural</span> <span class='conid'>Roll</span>
<span class='varop'>></span> <span class='keyglyph'>|</span> <span class='conid'>Pass</span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='keyglyph'>|</span> <span class='conid'>CrapOut</span> <span class='conid'>Roll</span>
<span class='varop'>></span> <span class='keyglyph'>|</span> <span class='conid'>SevenOut</span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='keyword'>deriving</span> <span class='conid'>Show</span>
</pre>
To generate a lazy list of rolls, pass a random-number generator (created, for example, with <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/random/System-Random.html#v%3AnewStdGen">newStdGen</a>, and use as many as you need. The second case in the definition of <code>go</code> silences a partial-function warning (“Pattern match(es) are non-exhaustive” with ghc), <i>viz.</i> empty and singleton lists. We'll always have at least two elements because <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/random/System-Random.html#v%3ArandomRs">randomRs</a> produces an infinite list of bounded random numbers.
<pre>
<span class='varop'>></span> <span class='varid'>rolls</span> <span class='keyglyph'>::</span> <span class='conid'>RandomGen</span> <span class='varid'>g</span> <span class='keyglyph'>=></span> <span class='varid'>g</span> <span class='keyglyph'>-></span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>rolls</span> <span class='varid'>g</span> <span class='keyglyph'>=</span> <span class='varid'>go</span> <span class='varop'>$</span> <span class='varid'>randomRs</span> <span class='layout'>(</span><span class='num'>1</span><span class='layout'>,</span><span class='num'>6</span><span class='layout'>)</span> <span class='varid'>g</span>
<span class='varop'>></span> <span class='keyword'>where</span>
<span class='varop'>></span> <span class='varid'>go</span> <span class='layout'>(</span><span class='varid'>a</span><span class='conop'>:</span><span class='varid'>b</span><span class='conop'>:</span><span class='varid'>xs</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='conid'>Roll</span> <span class='varid'>a</span> <span class='varid'>b</span> <span class='conop'>:</span> <span class='varid'>go</span> <span class='varid'>xs</span>
<span class='varop'>></span> <span class='varid'>go</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='varid'>undefined</span>
</pre>
Now that we have as many rolls as we want, let's separate them into games. For the trivial case, if you aren't rolling, you aren't playing:
<pre>
<span class='varop'>></span> <span class='varid'>games</span> <span class='keyglyph'>::</span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span> <span class='keyglyph'>-></span> <span class='keyglyph'>[</span><span class='conid'>Game</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>games</span> <span class='conid'>[]</span> <span class='keyglyph'>=</span> <span class='conid'>[]</span>
</pre>
Before the shooter establishes a point, we watch for magic numbers:
<pre>
<span class='varop'>></span> <span class='varid'>games</span> <span class='layout'>(</span><span class='varid'>r</span><span class='conop'>:</span><span class='varid'>rs</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>any</span> <span class='layout'>(</span><span class='varid'>rolled</span> <span class='varid'>r</span><span class='layout'>)</span> <span class='keyglyph'>[</span><span class='num'>7</span><span class='layout'>,</span><span class='num'>11</span><span class='keyglyph'>]</span> <span class='keyglyph'>=</span> <span class='conid'>Natural</span> <span class='varid'>r</span> <span class='conop'>:</span> <span class='varid'>games</span> <span class='varid'>rs</span>
<span class='varop'>></span> <span class='varid'>games</span> <span class='layout'>(</span><span class='varid'>r</span><span class='conop'>:</span><span class='varid'>rs</span><span class='layout'>)</span> <span class='keyglyph'>|</span> <span class='varid'>any</span> <span class='layout'>(</span><span class='varid'>rolled</span> <span class='varid'>r</span><span class='layout'>)</span> <span class='keyglyph'>[</span><span class='num'>2</span><span class='layout'>,</span><span class='num'>3</span><span class='layout'>,</span><span class='num'>12</span><span class='keyglyph'>]</span> <span class='keyglyph'>=</span> <span class='conid'>CrapOut</span> <span class='varid'>r</span> <span class='conop'>:</span> <span class='varid'>games</span> <span class='varid'>rs</span>
</pre>
Otherwise, whatever the shooter rolled becomes the point. The game ends when the shooter rolls 7 or makes the point.
<pre>
<span class='varop'>></span> <span class='varid'>games</span> <span class='layout'>(</span><span class='varid'>pt</span><span class='conop'>:</span><span class='varid'>rs</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>go</span> <span class='varid'>rest</span> <span class='conop'>:</span> <span class='varid'>games</span> <span class='varid'>rs'</span>
<span class='varop'>></span> <span class='keyword'>where</span>
</pre>
This inner <code>go</code> is also partial. If the list of rolls is finite, every point must be resolved, either pass or seven out. Note that the roll that ends the round will be the first element of the <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/Prelude.html#v%3Asnd">snd</a> of the pair we get from <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-List.html#v%3Abreak">break</a>, so we use pattern matching to grab it and tack it on the end of the round.
<pre>
<span class='varop'>></span> <span class='varid'>go</span> <span class='varid'>xs</span><span class='keyglyph'>@</span><span class='layout'>(</span><span class='varid'>final</span><span class='conop'>:</span><span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>outcome</span> <span class='varop'>$</span> <span class='varid'>reverse</span> <span class='varid'>xs</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>outcome</span> <span class='keyglyph'>|</span> <span class='varid'>final</span> <span class='varop'>`rolled`</span> <span class='num'>7</span> <span class='keyglyph'>=</span> <span class='conid'>SevenOut</span>
<span class='varop'>></span> <span class='keyglyph'>|</span> <span class='varid'>otherwise</span> <span class='keyglyph'>=</span> <span class='conid'>Pass</span>
<span class='varop'>></span> <span class='varid'>go</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='varid'>undefined</span>
<span class='varop'>></span> <span class='layout'>(</span><span class='varid'>ensuing</span><span class='layout'>,</span><span class='varid'>x</span><span class='conop'>:</span><span class='varid'>rs'</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>break</span> <span class='layout'>(</span><span class='keyglyph'>\</span><span class='varid'>r</span> <span class='keyglyph'>-></span> <span class='varid'>r</span> <span class='varop'>`rolled`</span> <span class='num'>7</span> <span class='varop'>||</span> <span class='varid'>r</span> <span class='varop'>`eq`</span> <span class='varid'>pt</span><span class='layout'>)</span> <span class='varid'>rs</span>
<span class='varop'>></span> <span class='varid'>rest</span> <span class='keyglyph'>=</span> <span class='varid'>x</span> <span class='conop'>:</span> <span class='varid'>reverse</span> <span class='layout'>(</span><span class='varid'>pt</span> <span class='conop'>:</span> <span class='varid'>ensuing</span><span class='layout'>)</span>
</pre>
<code>rolled</code> is a simple helper for testing whether the shooter rolled a particular number, <i>e.g.</i>, <code>r `rolled` 7</code> as seen above.
<pre>
<span class='varop'>></span> <span class='varid'>rolled</span> <span class='keyglyph'>::</span> <span class='conid'>Roll</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span> <span class='keyglyph'>-></span> <span class='conid'>Bool</span>
<span class='varop'>></span> <span class='varid'>rolled</span> <span class='varid'>r</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='varop'>==</span> <span class='varid'>total</span> <span class='varid'>r</span><span class='layout'>)</span>
</pre>
Two rolls are equal if they have the same total (yes, Lispers, I should have spelled it <code>equal</code>):
<pre>
<span class='varop'>></span> <span class='varid'>eq</span> <span class='keyglyph'>::</span> <span class='conid'>Roll</span> <span class='keyglyph'>-></span> <span class='conid'>Roll</span> <span class='keyglyph'>-></span> <span class='conid'>Bool</span>
<span class='varop'>></span> <span class='varid'>a</span> <span class='varop'>`eq`</span> <span class='varid'>b</span> <span class='keyglyph'>=</span> <span class='varid'>total</span> <span class='varid'>a</span> <span class='varop'>==</span> <span class='varid'>total</span> <span class='varid'>b</span>
<span class='varop'>></span> <span class='varid'>total</span> <span class='keyglyph'>::</span> <span class='conid'>Roll</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span>
<span class='varop'>></span> <span class='varid'>total</span> <span class='layout'>(</span><span class='conid'>Roll</span> <span class='varid'>a</span> <span class='varid'>b</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>a</span> <span class='varop'>+</span> <span class='varid'>b</span>
</pre>
Everything below is for testing with <a href="http://hackage.haskell.org/package/QuickCheck-1.2.0.0">classic QuickCheck</a>. Earlier iterations used this <a href="http://hackage.haskell.org/packages/archive/QuickCheck/1.2.0.0/doc/html/Test-QuickCheck.html#t%3AArbitrary">Arbitrary</a> instance, but now it's window dressing.
<pre>
<span class='varop'>></span> <span class='keyword'>instance</span> <span class='conid'>Arbitrary</span> <span class='conid'>Roll</span> <span class='keyword'>where</span>
<span class='varop'>></span> <span class='varid'>arbitrary</span> <span class='keyglyph'>=</span> <span class='keyword'>do</span> <span class='varid'>a</span> <span class='keyglyph'><-</span> <span class='varid'>choose</span> <span class='layout'>(</span><span class='num'>1</span><span class='layout'>,</span><span class='num'>6</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>b</span> <span class='keyglyph'><-</span> <span class='varid'>choose</span> <span class='layout'>(</span><span class='num'>1</span><span class='layout'>,</span><span class='num'>6</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>return</span> <span class='varop'>$</span> <span class='conid'>Roll</span> <span class='varid'>a</span> <span class='varid'>b</span>
<span class='varop'>></span> <span class='varid'>coarbitrary</span> <span class='keyglyph'>=</span> <span class='varid'>undefined</span>
</pre>
<code>vectorOf</code> turns a generator's crank a few times. We'll use this to generate multiple non-point rolls, for example. Note the use of <a href="http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Monad.html#v%3Asequence">sequence</a> to allow pseudo-random number generator state to update between rolls.
<pre>
<span class='varop'>></span> <span class='varid'>vectorOf</span> <span class='keyglyph'>::</span> <span class='conid'>Int</span> <span class='keyglyph'>-></span> <span class='conid'>Gen</span> <span class='varid'>a</span> <span class='keyglyph'>-></span> <span class='conid'>Gen</span> <span class='keyglyph'>[</span><span class='varid'>a</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>vectorOf</span> <span class='varid'>n</span> <span class='varid'>gs</span> <span class='keyglyph'>=</span> <span class='varid'>sequence</span> <span class='keyglyph'>[</span> <span class='varid'>gs</span> <span class='keyglyph'>|</span> <span class='keyword'>_</span> <span class='keyglyph'><-</span> <span class='keyglyph'>[</span><span class='num'>1</span><span class='keyglyph'>..</span><span class='varid'>n</span><span class='keyglyph'>]</span> <span class='keyglyph'>]</span>
</pre>
After the come-out roll establishes a point, the difference between a win and a loss is whether the game's last roll is 7 or the point. If <code>pass</code> is true, we generate a winner, otherwise a loser.
<pre>
<span class='varop'>></span> <span class='varid'>afterComeOut</span> <span class='keyglyph'>::</span> <span class='conid'>Bool</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span> <span class='keyglyph'>-></span> <span class='conid'>Gen</span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>afterComeOut</span> <span class='varid'>pass</span> <span class='varid'>n</span> <span class='keyglyph'>=</span> <span class='keyword'>do</span>
<span class='varop'>></span> <span class='varid'>n'</span> <span class='keyglyph'><-</span> <span class='varid'>choose</span> <span class='layout'>(</span><span class='num'>1</span><span class='layout'>,</span><span class='varid'>n</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>pt</span> <span class='keyglyph'><-</span> <span class='varid'>oneof</span> <span class='varid'>points</span>
<span class='varop'>></span> <span class='varid'>rs</span> <span class='keyglyph'><-</span> <span class='varid'>vectorOf</span> <span class='varid'>n'</span> <span class='layout'>(</span><span class='varid'>oneof</span> <span class='varop'>$</span> <span class='varid'>noPoint</span> <span class='varid'>pt</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>let</span> <span class='varid'>rollpt</span> <span class='keyglyph'>=</span> <span class='varid'>mkRoll</span> <span class='varid'>pt</span>
<span class='varop'>></span> <span class='varid'>final</span> <span class='keyglyph'>=</span> <span class='keyword'>if</span> <span class='varid'>pass</span> <span class='keyword'>then</span> <span class='varid'>rollpt</span> <span class='keyword'>else</span> <span class='varid'>seven</span>
<span class='varop'>></span> <span class='varid'>return</span> <span class='varop'>$</span> <span class='varid'>rollpt</span> <span class='conop'>:</span> <span class='varid'>rs</span> <span class='varop'>++</span> <span class='keyglyph'>[</span><span class='varid'>final</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='keyword'>where</span>
<span class='varop'>></span> <span class='varid'>noPoint</span> <span class='varid'>p</span> <span class='keyglyph'>=</span> <span class='varid'>mayroll</span> <span class='varop'>$</span> <span class='varid'>except</span> <span class='keyglyph'>[</span><span class='num'>7</span><span class='layout'>,</span><span class='varid'>p</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>points</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='varid'>return</span> <span class='varop'>$</span> <span class='varid'>except</span> <span class='keyglyph'>[</span><span class='num'>2</span><span class='layout'>,</span><span class='num'>3</span><span class='layout'>,</span><span class='num'>7</span><span class='layout'>,</span><span class='num'>11</span><span class='layout'>,</span><span class='num'>12</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>seven</span> <span class='keyglyph'>=</span> <span class='conid'>Roll</span> <span class='num'>3</span> <span class='num'>4</span>
<span class='varop'>></span> <span class='varid'>except</span> <span class='keyglyph'>=</span> <span class='layout'>(</span><span class='keyglyph'>[</span><span class='num'>2</span><span class='keyglyph'>..</span><span class='num'>12</span><span class='keyglyph'>]</span> <span class='varop'>\\</span><span class='layout'>)</span>
</pre>
Our testing strategy will be to generate games of all four types and then make sure they're correctly recognized. For example, the test for passes will use <code>expect isPass ...</code>
<pre>
<span class='varop'>></span> <span class='varid'>expect</span> <span class='keyglyph'>::</span> <span class='layout'>(</span><span class='conid'>Game</span> <span class='keyglyph'>-></span> <span class='conid'>Bool</span><span class='layout'>)</span> <span class='keyglyph'>-></span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span> <span class='keyglyph'>-></span> <span class='conid'>Bool</span>
<span class='varop'>></span> <span class='varid'>expect</span> <span class='varid'>what</span> <span class='keyglyph'>=</span> <span class='varid'>all</span> <span class='varid'>what</span> <span class='varop'>.</span> <span class='varid'>games</span>
</pre>
<code>mayroll</code> creates a list of generators ultimately for use with <a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/manual_body.html#14">oneof</a>, <i>e.g.</i>, <code>mayroll [2,3,12]</code> in the crap-out property.
<pre>
<span class='varop'>></span> <span class='varid'>mayroll</span> <span class='keyglyph'>::</span> <span class='keyglyph'>[</span><span class='conid'>Int</span><span class='keyglyph'>]</span> <span class='keyglyph'>-></span> <span class='keyglyph'>[</span><span class='conid'>Gen</span> <span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>mayroll</span> <span class='keyglyph'>=</span> <span class='varid'>map</span> <span class='layout'>(</span><span class='varid'>return</span> <span class='varop'>.</span> <span class='varid'>mkRoll</span><span class='layout'>)</span>
</pre>
QuickCheck opens the throttle on the size of testcases with <a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/manual_body.html#15">sized</a>, and <code>many</code> connects to this hook.
<pre>
<span class='varop'>></span> <span class='varid'>many</span> <span class='keyglyph'>::</span> <span class='keyglyph'>[</span><span class='conid'>Gen</span> <span class='conid'>Roll</span><span class='keyglyph'>]</span> <span class='keyglyph'>-></span> <span class='conid'>Int</span> <span class='keyglyph'>-></span> <span class='conid'>Gen</span> <span class='keyglyph'>[</span><span class='conid'>Roll</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>many</span> <span class='varid'>what</span> <span class='varid'>n</span> <span class='keyglyph'>=</span> <span class='keyword'>do</span>
<span class='varop'>></span> <span class='varid'>n'</span> <span class='keyglyph'><-</span> <span class='varid'>choose</span> <span class='layout'>(</span><span class='num'>1</span><span class='layout'>,</span><span class='varid'>n</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='varid'>vectorOf</span> <span class='varid'>n'</span> <span class='layout'>(</span><span class='varid'>oneof</span> <span class='varid'>what</span><span class='layout'>)</span>
</pre>
<code>mkRoll</code> starts from a roll total and backs into the individual components. An obvious improvement would be adding choices other than 1 and 6.
<pre>
<span class='varop'>></span> <span class='varid'>mkRoll</span> <span class='keyglyph'>::</span> <span class='conid'>Int</span> <span class='keyglyph'>-></span> <span class='conid'>Roll</span>
<span class='varop'>></span> <span class='varid'>mkRoll</span> <span class='varid'>t</span> <span class='keyglyph'>=</span> <span class='conid'>Roll</span> <span class='varid'>less</span> <span class='layout'>(</span><span class='varid'>t</span> <span class='comment'>-</span> <span class='varid'>less</span><span class='layout'>)</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>less</span> <span class='keyglyph'>|</span> <span class='varid'>t</span> <span class='varop'><=</span> <span class='num'>6</span> <span class='keyglyph'>=</span> <span class='num'>1</span>
<span class='varop'>></span> <span class='keyglyph'>|</span> <span class='varid'>otherwise</span> <span class='keyglyph'>=</span> <span class='num'>6</span>
</pre>
Now we get to the properties that use QuickCheck's <a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/manual_body.html#7">forAll</a> to generate random test data of the appropriate class and check for the expected results.
<pre>
<span class='varop'>></span> <span class='varid'>prop_crapOut</span> <span class='keyglyph'>::</span> <span class='conid'>Property</span>
<span class='varop'>></span> <span class='varid'>prop_crapOut</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='varid'>forAll</span> <span class='varid'>allCraps</span> <span class='varop'>$</span> <span class='varid'>expect</span> <span class='varid'>isCrapOut</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>isCrapOut</span> <span class='layout'>(</span><span class='conid'>CrapOut</span> <span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='conid'>True</span>
<span class='varop'>></span> <span class='varid'>isCrapOut</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='conid'>False</span>
<span class='varop'>></span> <span class='varid'>allCraps</span> <span class='keyglyph'>=</span> <span class='varid'>sized</span> <span class='varop'>$</span> <span class='varid'>many</span> <span class='varid'>craps</span>
<span class='varop'>></span> <span class='varid'>craps</span> <span class='keyglyph'>=</span> <span class='varid'>mayroll</span> <span class='keyglyph'>[</span><span class='num'>2</span><span class='layout'>,</span><span class='num'>3</span><span class='layout'>,</span><span class='num'>12</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>prop_natural</span> <span class='keyglyph'>::</span> <span class='conid'>Property</span>
<span class='varop'>></span> <span class='varid'>prop_natural</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='varid'>forAll</span> <span class='varid'>allNats</span> <span class='varop'>$</span> <span class='varid'>expect</span> <span class='varid'>isNat</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>isNat</span> <span class='layout'>(</span><span class='conid'>Natural</span> <span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='conid'>True</span>
<span class='varop'>></span> <span class='varid'>isNat</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='conid'>False</span>
<span class='varop'>></span> <span class='varid'>allNats</span> <span class='keyglyph'>=</span> <span class='varid'>sized</span> <span class='varop'>$</span> <span class='varid'>many</span> <span class='varid'>nats</span>
<span class='varop'>></span> <span class='varid'>nats</span> <span class='keyglyph'>=</span> <span class='varid'>mayroll</span> <span class='keyglyph'>[</span><span class='num'>7</span><span class='layout'>,</span><span class='num'>11</span><span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='varid'>prop_sevenOut</span> <span class='keyglyph'>::</span> <span class='conid'>Property</span>
<span class='varop'>></span> <span class='varid'>prop_sevenOut</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='varid'>forAll</span> <span class='varid'>allSevenOuts</span> <span class='varop'>$</span> <span class='varid'>expect</span> <span class='varid'>is7Out</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>is7Out</span> <span class='layout'>(</span><span class='conid'>SevenOut</span> <span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='conid'>True</span>
<span class='varop'>></span> <span class='varid'>is7Out</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='conid'>False</span>
<span class='varop'>></span> <span class='varid'>allSevenOuts</span> <span class='keyglyph'>=</span> <span class='varid'>sized</span> <span class='varop'>$</span> <span class='varid'>afterComeOut</span> <span class='conid'>False</span>
<span class='varop'>></span> <span class='varid'>prop_pass</span> <span class='keyglyph'>::</span> <span class='conid'>Property</span>
<span class='varop'>></span> <span class='varid'>prop_pass</span> <span class='keyglyph'>=</span>
<span class='varop'>></span> <span class='varid'>forAll</span> <span class='varid'>allPasses</span> <span class='varop'>$</span> <span class='varid'>expect</span> <span class='varid'>isPass</span>
<span class='varop'>></span> <span class='keyword'>where</span> <span class='varid'>isPass</span> <span class='layout'>(</span><span class='conid'>Pass</span> <span class='keyword'>_</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='conid'>True</span>
<span class='varop'>></span> <span class='varid'>isPass</span> <span class='keyword'>_</span> <span class='keyglyph'>=</span> <span class='conid'>False</span>
<span class='varop'>></span> <span class='varid'>allPasses</span> <span class='keyglyph'>=</span> <span class='varid'>sized</span> <span class='varop'>$</span> <span class='varid'>afterComeOut</span> <span class='conid'>True</span>
</pre>
Finally, a simple test driver so we don't have to check them one-by-one:
<pre>
<span class='varop'>></span> <span class='varid'>runTests</span> <span class='keyglyph'>::</span> <span class='conid'>IO</span> <span class='conid'>()</span>
<span class='varop'>></span> <span class='varid'>runTests</span> <span class='keyglyph'>=</span> <span class='keyword'>do</span>
<span class='varop'>></span> <span class='keyword'>let</span> <span class='varid'>opts</span> <span class='keyglyph'>=</span> <span class='varid'>defOpt</span> <span class='layout'>{</span> <span class='varid'>no_of_tests</span> <span class='keyglyph'>=</span> <span class='num'>200</span> <span class='layout'>}</span>
<span class='varop'>></span> <span class='conid'>QC</span><span class='varop'>.</span><span class='varid'>runTests</span> <span class='str'>"crap out"</span> <span class='varid'>opts</span> <span class='keyglyph'>[</span> <span class='varid'>run</span> <span class='varid'>prop_crapOut</span> <span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='conid'>QC</span><span class='varop'>.</span><span class='varid'>runTests</span> <span class='str'>"natural"</span> <span class='varid'>opts</span> <span class='keyglyph'>[</span> <span class='varid'>run</span> <span class='varid'>prop_natural</span> <span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='conid'>QC</span><span class='varop'>.</span><span class='varid'>runTests</span> <span class='str'>"seven out"</span> <span class='varid'>opts</span> <span class='keyglyph'>[</span> <span class='varid'>run</span> <span class='varid'>prop_sevenOut</span> <span class='keyglyph'>]</span>
<span class='varop'>></span> <span class='conid'>QC</span><span class='varop'>.</span><span class='varid'>runTests</span> <span class='str'>"pass"</span> <span class='varid'>opts</span> <span class='keyglyph'>[</span> <span class='varid'>run</span> <span class='varid'>prop_pass</span> <span class='keyglyph'>]</span>
</pre>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-68624441625332885182009-09-16T15:37:00.007-05:002009-09-16T16:17:32.202-05:00MediaWiki Collection extension: load saved booksAt work, we're using the <a href="http://www.mediawiki.org/wiki/Extension:Collection">Collection extension</a> for MediaWiki to render PDF versions of our documentation.
<p>
Installation went smoothly. We were able to generate nice-looking PDFs for single pages, create “books” with chapters and subsections, and save the books. After we'd gone to all the trouble of organizing the books, the reader might understand our frustration in seeing no obvious way to load our books later.
</p><p>
After much Googling and prodding around the source, I noticed a passage at the bottom of the <a href="http://svn.wikimedia.org/svnroot/mediawiki/trunk/extensions/Collection/README.txt">README</a>:
</p><blockquote>
<ul><li>Add a template [[Template:saved_book]] which is transcluded on top of saved
collection pages. An example for such a template can be found on the English
Wikipedia: <a href="http://en.wikipedia.org/wiki/Template:Saved_book">http://en.wikipedia.org/wiki/Template:Saved_book</a></li></ul>
</blockquote>
The Wikipedia template has lots of nice chrome, but for a quick fix, edit Template:Saved_book to have the following contents:
<p>
<span style="font-family:monospace;"><span style="color: rgb(0, 139, 139);"><</span><span style="color: rgb(165, 42, 42);"><b>div</b></span><span style="color: rgb(0, 139, 139);"> </span><span style="color: rgb(46, 139, 87);"><b>align</b></span><span style="color: rgb(0, 139, 139);">=</span><span style="color: rgb(255, 0, 255);">"center"</span><span style="color: rgb(0, 139, 139);">></span><br>
<span style="color: rgb(0, 139, 139);"><</span><span style="color: rgb(165, 42, 42);"><b>span</b></span><span style="color: rgb(0, 139, 139);"> </span><span style="color: rgb(46, 139, 87);"><b>class</b></span><span style="color: rgb(0, 139, 139);">=</span><span style="color: rgb(255, 0, 255);">"plainlinks"</span><span style="color: rgb(0, 139, 139);">></span><br>
[ [{{fullurl:Special:Book/load_collection/|colltitle={{FULLPAGENAMEE}}}} load book] ] <span style="color: rgb(106, 90, 205);">&nbsp;&nbsp;</span><br>
[ [{{fullurl:Special:Book/render_collection/|colltitle={{FULLPAGENAMEE}}<span style="color: rgb(106, 90, 205);">&amp;</span>writer=rl}} PDF] ] <span style="color: rgb(106, 90, 205);">&nbsp;&nbsp;</span><br>
[ [{{fullurl:Special:Book/render_collection/|colltitle={{FULLPAGENAMEE}}<span style="color: rgb(106, 90, 205);">&amp;</span>writer=odf}} OpenOffice] ] <span style="color: rgb(106, 90, 205);">&nbsp;&nbsp;</span><br>
[ [[:Category:Books|bookshelf]] <span style="color: rgb(106, 90, 205);">&nbsp;</span>]<br>
<span style="color: rgb(0, 139, 139);"></</span><span style="color: rgb(165, 42, 42);"><b>span</b></span><span style="color: rgb(0, 139, 139);">></span><br>
<span style="color: rgb(0, 139, 139);"></</span><span style="color: rgb(165, 42, 42);"><b>div</b></span><span style="color: rgb(0, 139, 139);">></span>
</span>
<p>
This will be transcluded into your saved book pages (via <code>{{saved_book}}</code> at the very top) and produce handy links for loading, generating PDF, generating ODT, or browsing the rest of your saved books, as in
</p>
<p align="center">[ <a href="http://gbacon.blogspot.com/2009/09/mediawiki-collection-extension-load.html">load book</a> ] [ <a href="http://gbacon.blogspot.com/2009/09/mediawiki-collection-extension-load.html">PDF</a> ] [ <a href="http://gbacon.blogspot.com/2009/09/mediawiki-collection-extension-load.html">OpenOffice</a> ] [ <a href="http://gbacon.blogspot.com/2009/09/mediawiki-collection-extension-load.html">bookshelf</a> ]</p>
<p>
Note that to enable ODT option, you'll need to modify <code>LocalSettings.php</code> along the lines of
</p><p>
<span style="font-family:monospace;"> <span style="color: rgb(165, 42, 42);"><b>$</b></span><span style="color: rgb(0, 139, 139);">wgCollectionFormats</span> <span style="color: rgb(165, 42, 42);"><b>=</b></span> <span style="color: rgb(46, 139, 87);"><b>array</b></span><span style="color: rgb(106, 90, 205);">(</span><br>
'<span style="color: rgb(255, 0, 255);">rl</span>' <span style="color: rgb(165, 42, 42);"><b>=</b></span><span style="color: rgb(165, 42, 42);"><b>></b></span> '<span style="color: rgb(255, 0, 255);">PDF</span>',<br>
'<span style="color: rgb(255, 0, 255);">odf</span>' <span style="color: rgb(165, 42, 42);"><b>=</b></span><span style="color: rgb(165, 42, 42);"><b>></b></span> '<span style="color: rgb(255, 0, 255);">ODT</span>',<br>
<span style="color: rgb(106, 90, 205);">)</span>;</span></p>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-55908113168734111252009-09-15T17:21:00.003-05:002009-09-15T17:52:03.116-05:00Don't repeat yourself!<a href="http://perliscope.blogspot.com/2009/09/using-modern-perl.html">Jose Rey demonstrates a few features of Perl 5.10</a>, but all the nearly identical actions scream for <a href="http://perldoc.perl.org/perlsyn.html#Smart-matching-in-detail">smart matching</a>!
<p>
<font face="monospace"><font color="#0000ff"># ...</font><br>
<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">%func</font>;<br>
<font color="#008b8b">@func</font>{<font color="#ff00ff">qw(</font><font color="#ff00ff"> count geometric_mean harmonic_mean</font><br>
<font color="#ff00ff"> max maxdex mean</font><br>
<font color="#ff00ff"> median min mindex</font><br>
<font color="#ff00ff"> mode sample_range standard_deviation</font><br>
<font color="#ff00ff"> sum trimmed_mean variance </font><font color="#ff00ff">)</font>} = ();<br>
<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$s</font> = Statistics::Descriptive::Full-><font color="#a52a2a"><b>new</b></font>();<br>
<font color="#a52a2a"><b>while</b></font> (<font color="#ff00ff">1</font>) {<br>
<font color="#a52a2a"><b>print</b></font> <font color="#ff00ff">"</font><font color="#ff00ff">Listo> </font><font color="#ff00ff">"</font>;<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$command</font> = <font color="#a52a2a"><b>readline</b></font>(<font color="#008b8b">STDIN</font>) <font color="#a52a2a"><b>//</b></font> <font color="#a52a2a"><b>last</b></font>;<br>
<font color="#008b8b">$command</font> =~ <font color="#a52a2a"><b>s/</b></font><font color="#ff00ff">^</font><font color="#6a5acd">\s</font><font color="#6a5acd">+</font><font color="#a52a2a"><b>//</b></font>; <font color="#008b8b">$command</font> =~ <font color="#a52a2a"><b>s/</b></font><font color="#6a5acd">\s</font><font color="#6a5acd">+</font><font color="#ff00ff">$</font><font color="#a52a2a"><b>//</b></font>;<br>
given (<font color="#008b8b">$command</font>) {<br>
when ( looks_like_number(<font color="#008b8b">$_</font>) ) { <font color="#008b8b">$s</font>->add_data(<font color="#008b8b">$command</font>) }<br>
when (<font color="#008b8b">%func</font>) { say <font color="#ff00ff">"</font><font color="#008b8b">$command</font><font color="#ff00ff"> = </font><font color="#ff00ff">"</font> . <font color="#008b8b">$s</font>-><font color="#008b8b">$command</font>() }<br>
when (<font color="#a52a2a"><b>/</b></font><font color="#ff00ff">^</font><font color="#6a5acd">(</font><font color="#ff00ff">exit|quit</font><font color="#6a5acd">)</font><font color="#ff00ff">$</font><font color="#a52a2a"><b>/</b></font>) {<font color="#a52a2a"><b>last</b></font>}<br>
default { say SYNTAX_ERROR }<br>
}<br>
}</font>
<p>
As the <a href="http://perldoc.perl.org/perlsyn.html#Smart-matching-in-detail">smart-match table</a> shows, <code>$scalar ~~ %hash</code> tests for hash-key existence. In this case, <code>given ($command)</code> followed by <code>when (%func)</code> checks whether the current command is a builtin and, when it is, invokes the method with the same name.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-68835061174669019782009-08-31T07:00:00.008-05:002009-08-31T15:18:50.311-05:00Finding duplicates with Perl and HaskellA coworker wanted to check a family of log files to be sure that a given task never appeared on multiple nodes at the same time. Log entries are on single, whitespace-separated lines, and the last field records a task's start time, <i>e.g.</i>,
<pre>1251475056672590000_1732248586_4</pre>
Of the three underscore-separated fields, the first is a timestamp, the second we don't care about, and the third is a task identifier.
<p>
This task is straightforward with Perl. The diamond operator (or <a href="http://perldoc.perl.org/perlop.html#I%2fO-Operators">null filehandle, as described in the "I/O Operators" section of the perlop manpage</a>) takes care of the boilerplate for iterating over the paths on the command line, opening them, and reading each line. The scalar <tt>$ARGV</tt> contains the name of the current file.
<p>
By default, <a href="http://perldoc.perl.org/functions/split.html">split</a> separates fields by whitespace, so <tt>(split)[-1]</tt> gives us the last field, from which we then grab the time and task with a regular expression and record its presence by <a href="http://perldoc.perl.org/functions/push.html">pushing</a> the entry's path and line number onto an array associated with that time/task pair. After we've processed the logs, these arrays should all be singletons.
<p>
The continue clause is a little weird but necessary because the <a href="http://perldoc.perl.org/perlvar.html#%24.">special variable <tt>$.</tt></a>, the current line number, does not reset on <tt><></tt>'s implicit opens. <tt>ARGV</tt> is a handle on the file being read.
<p>
With this data structure, detecting duplicates is a search for time/task pairs with multiple hits. We count duplicates and let the user know what we found.
<p>
<font face="monospace">
<font color="#a020f0">#! /usr/bin/perl</font><br>
<br>
<font color="#a52a2a"><b>use warnings</b></font>;<br>
<font color="#a52a2a"><b>use strict</b></font>;<br>
<br>
<font color="#0000ff"># e.g., $hits = @{ $seen{$time}{$task} };</font><br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">%seen</font>;<br>
<br>
<font color="#a52a2a"><b>sub</b></font><font color="#008b8b"> </font><font color="#008b8b">num</font><font color="#008b8b"> </font>{ <font color="#008b8b">$a</font> <=> <font color="#008b8b">$b</font> }<br>
<br>
<font color="#a52a2a"><b>while</b></font> (<>) {<br>
<font color="#a52a2a"><b>if</b></font> ((<font color="#a52a2a"><b>split</b></font>)[<font color="#ff00ff">-1</font>] =~<font color="#a52a2a"><b> /</b></font><font color="#ff00ff">^</font><font color="#6a5acd">(</font><font color="#6a5acd">\d</font><font color="#6a5acd">+)</font><font color="#ff00ff">_</font><font color="#6a5acd">\d</font><font color="#6a5acd">+</font><font color="#ff00ff">_</font><font color="#6a5acd">(</font><font color="#6a5acd">\d</font><font color="#6a5acd">+)</font><font color="#ff00ff">$</font><font color="#a52a2a"><b>/</b></font>) {<br>
<font color="#a52a2a"><b>my</b></font>(<font color="#008b8b">$time</font>,<font color="#008b8b">$task</font>) = (<font color="#008b8b">$1</font>,<font color="#008b8b">$2</font>);<br>
<font color="#a52a2a"><b>push</b></font> @{ <font color="#008b8b">$seen</font>{<font color="#008b8b">$time</font>}{<font color="#008b8b">$task</font>} } => <font color="#ff00ff">"</font><font color="#008b8b">$ARGV</font><font color="#ff00ff">:</font><font color="#008b8b">$.</font><font color="#ff00ff">"</font>;<br>
}<br>
<font color="#a52a2a"><b>else</b></font> {<br>
<font color="#a52a2a"><b>die</b></font> <font color="#ff00ff">"</font><font color="#008b8b">$0</font><font color="#ff00ff">: </font><font color="#008b8b">$ARGV</font><font color="#ff00ff">:</font><font color="#008b8b">$.</font><font color="#ff00ff">: bad timestamp/task field</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>;<br>
}<br>
}<br>
<font color="#a52a2a"><b>continue</b></font> {<br>
<font color="#a52a2a"><b>close</b></font> <font color="#008b8b">ARGV</font> <font color="#a52a2a"><b>if</b></font> <font color="#a52a2a"><b>eof</b></font>;<br>
}<br>
<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$duplicates</font> = <font color="#ff00ff">0</font>;<br>
<font color="#a52a2a"><b>foreach</b></font> <font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$time</font> (<font color="#a52a2a"><b>sort</b></font> num <font color="#a52a2a"><b>keys</b></font> <font color="#008b8b">%seen</font>) {<br>
<font color="#a52a2a"><b>foreach</b></font> <font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$task</font> (<font color="#a52a2a"><b>sort</b></font> num <font color="#a52a2a"><b>keys</b></font> %{ <font color="#008b8b">$seen</font>{<font color="#008b8b">$time</font>} }) {<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">@hits</font> = @{ <font color="#008b8b">$seen</font>{<font color="#008b8b">$time</font>}{<font color="#008b8b">$task</font>} };<br>
<font color="#a52a2a"><b>next</b></font> <font color="#a52a2a"><b>if</b></font> <font color="#008b8b">@hits</font> == <font color="#ff00ff">1</font>;<br>
<br>
<font color="#008b8b">$duplicates</font> += <font color="#008b8b">@hits</font> - <font color="#ff00ff">1</font>;<br>
<font color="#a52a2a"><b>warn</b></font> <font color="#ff00ff">"</font><font color="#008b8b">$0</font><font color="#ff00ff">: duplicates for time=</font><font color="#008b8b">$time</font><font color="#ff00ff">, task=</font><font color="#008b8b">$task</font><font color="#ff00ff">:</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>,<br>
<font color="#a52a2a"><b>map</b></font> <font color="#ff00ff">"</font><font color="#ff00ff"> - </font><font color="#008b8b">$_</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>, <font color="#008b8b">@hits</font>;<br>
}<br>
}<br>
<br>
<font color="#a52a2a"><b>my</b></font> <font color="#008b8b">$s</font> = <font color="#008b8b">$duplicates</font> == <font color="#ff00ff">1</font> ? <font color="#ff00ff">""</font> : <font color="#ff00ff">"</font><font color="#ff00ff">s</font><font color="#ff00ff">"</font>;<br>
<font color="#a52a2a"><b>print</b></font> <font color="#ff00ff">"</font><font color="#008b8b">$0</font><font color="#ff00ff">: </font><font color="#008b8b">$duplicates</font><font color="#ff00ff"> duplicate</font><font color="#008b8b">$s</font><font color="#ff00ff"> detected.</font><font color="#6a5acd">\n</font><font color="#ff00ff">"</font>;<br>
<br>
<font color="#a52a2a"><b>exit</b></font> <font color="#008b8b">$duplicates</font> == <font color="#ff00ff">0</font> ? <font color="#ff00ff">0</font> : <font color="#ff00ff">1</font>;<br>
</font>
<p>
For comparison, I implemented the same log checker in Haskell. The function <tt>allInputs</tt> emulates Perl's diamond operator, and instead of a multi-level hash, the association is more direct: time/task pair to a list of hits.
<p>
<font face="monospace">
<font color="#2e8b57"><b>module</b></font> Main <font color="#2e8b57"><b>where</b></font><br>
<br>
<font color="#a020f0">import</font> Control.Monad (liftM)<br>
<font color="#a020f0">import</font> Data.List (sort)<br>
<font color="#a020f0">import</font> Data.Map (empty,filter,fromListWith,toList,unionWith)<br>
<font color="#a020f0">import</font> Prelude <font color="#a020f0">hiding</font> (filter)<br>
<font color="#a020f0">import</font> System.Environment (getArgs,getProgName)<br>
<font color="#a020f0">import</font> System.Exit (ExitCode(..),exitWith)<br>
<font color="#a020f0">import</font> Text.Printf (printf)<br>
<br>
<font color="#2e8b57"><b>type</b></font> Time <font color="#a52a2a"><b>=</b></font> String<br>
<font color="#2e8b57"><b>type</b></font> Task <font color="#a52a2a"><b>=</b></font> String<br>
<font color="#2e8b57"><b>data</b></font> Duplicates <font color="#a52a2a"><b>=</b></font><br>
Duplicates { timestamp <font color="#a52a2a"><b>::</b></font> Time<br>
, taskId <font color="#a52a2a"><b>::</b></font> Task<br>
, locations <font color="#a52a2a"><b>::</b></font> [(FilePath, Int)]<br>
}<br>
<br>
main <font color="#a52a2a"><b>::</b></font> IO ()<br>
main <font color="#a52a2a"><b>=</b></font> <font color="#a52a2a"><b>do</b></font><br>
logs <font color="#a52a2a"><b><-</b></font> allInputs<br>
<font color="#a52a2a"><b>let</b></font> multi <font color="#a52a2a"><b>=</b></font> dups logs<br>
n <font color="#a52a2a"><b>=</b></font> sum <font color="#a52a2a"><b>$</b></font> map (subtract <font color="#ff00ff">1</font> <font color="#a52a2a"><b>.</b></font> length <font color="#a52a2a"><b>.</b></font> locations) multi<br>
mapM_ (msg <font color="#a52a2a"><b>.</b></font> lines <font color="#a52a2a"><b>.</b></font> dupmsg) multi<br>
msg <font color="#a52a2a"><b>$</b></font> ndups n<br>
exitWith <font color="#a52a2a"><b>$</b></font> <font color="#a52a2a"><b>if</b></font> n <font color="#a52a2a"><b>==</b></font> <font color="#ff00ff">0</font><br>
<font color="#a52a2a"><b>then</b></font> ExitSuccess<br>
<font color="#a52a2a"><b>else</b></font> ExitFailure <font color="#ff00ff">1</font><br>
<font color="#2e8b57"><b>where</b></font><br>
msg info <font color="#a52a2a"><b>=</b></font> <font color="#a52a2a"><b>do</b></font> me <font color="#a52a2a"><b><-</b></font> getProgName<br>
putStrLn <font color="#a52a2a"><b>$</b></font> me <font color="#a52a2a"><b>++</b></font> <font color="#ff00ff">": "</font> <font color="#a52a2a"><b>++</b></font> head info<br>
mapM_ putStrLn (tail info)<br>
<br>
ndups <font color="#ff00ff">1</font> <font color="#a52a2a"><b>=</b></font> [<font color="#ff00ff">"1 duplicate detected"</font>]<br>
ndups n <font color="#a52a2a"><b>=</b></font> [show n <font color="#a52a2a"><b>++</b></font> <font color="#ff00ff">" duplicates detected"</font>]<br>
<br>
dupmsg (Duplicates tm task ls) <font color="#a52a2a"><b>=</b></font> unlines <font color="#a52a2a"><b>$</b></font><br>
printf <font color="#ff00ff">"duplicates for time=%s, task=%s:"</font> tm task <font color="#a52a2a"><b>:</b></font><br>
map (<font color="#a52a2a"><b>\</b></font>(path,n) <font color="#a52a2a"><b>-></b></font> printf <font color="#ff00ff">" - %s:%d"</font> path n) ls<br>
<br>
allInputs <font color="#a52a2a"><b>::</b></font> IO [(FilePath, String)]<br>
allInputs <font color="#a52a2a"><b>=</b></font> getArgs <font color="#a52a2a"><b>>>=</b></font> go<br>
<font color="#2e8b57"><b>where</b></font> go [] <font color="#a52a2a"><b>=</b></font> ((<font color="#a52a2a"><b>:</b></font>[]) <font color="#a52a2a"><b>.</b></font> (,) <font color="#ff00ff">"-"</font>) <font color="#a52a2a"><b>`liftM`</b></font> getContents<br>
go fs <font color="#a52a2a"><b>=</b></font> mapM readFile fs <font color="#a52a2a"><b>>>=</b></font> return <font color="#a52a2a"><b>.</b></font> zip fs<br>
<br>
dups <font color="#a52a2a"><b>::</b></font> [(FilePath, String)] <font color="#a52a2a"><b>-></b></font> [Duplicates]<br>
dups <font color="#a52a2a"><b>=</b></font> map (<font color="#a52a2a"><b>\</b></font>((tm,task),ds) <font color="#a52a2a"><b>-></b></font> Duplicates tm task ds) <font color="#a52a2a"><b>.</b></font><br>
sort <font color="#a52a2a"><b>.</b></font><br>
toList <font color="#a52a2a"><b>.</b></font><br>
filter ((<font color="#a52a2a"><b>></b></font> <font color="#ff00ff">1</font>) <font color="#a52a2a"><b>.</b></font> length) <font color="#a52a2a"><b>.</b></font><br>
foldl (unionWith (<font color="#a52a2a"><b>++</b></font>)) empty <font color="#a52a2a"><b>.</b></font><br>
map (<font color="#a52a2a"><b>\</b></font>(path, contents) <font color="#a52a2a"><b>-></b></font><br>
fromListWith (<font color="#a52a2a"><b>++</b></font>) <font color="#a52a2a"><b>$</b></font><br>
map (wrap path <font color="#a52a2a"><b>.</b></font> getTimeTask) <font color="#a52a2a"><b>$</b></font><br>
zip [<font color="#ff00ff">1</font><font color="#a52a2a"><b>..</b></font>] <font color="#a52a2a"><b>$</b></font> lines contents)<br>
<font color="#2e8b57"><b>where</b></font><br>
wrap path (tm,task,n) <font color="#a52a2a"><b>=</b></font> ((tm,task), [(path,n)])<br>
<br>
getTimeTask <font color="#a52a2a"><b>::</b></font> (Int,String) <font color="#a52a2a"><b>-></b></font> (Time,Task,Int)<br>
getTimeTask (n,line) <font color="#a52a2a"><b>=</b></font> (tm,tsk,n)<br>
<font color="#2e8b57"><b>where</b></font><br>
[tm,_,tsk] <font color="#a52a2a"><b>=</b></font> splitBy <font color="#ff00ff">'_'</font> (last <font color="#a52a2a"><b>$</b></font> words line)<br>
<br>
splitBy <font color="#a52a2a"><b>::</b></font> Eq a <font color="#a52a2a"><b>=></b></font> a <font color="#a52a2a"><b>-></b></font> [a] <font color="#a52a2a"><b>-></b></font> [[a]]<br>
splitBy _ [] <font color="#a52a2a"><b>=</b></font> []<br>
splitBy x xs <font color="#a52a2a"><b>=</b></font> h <font color="#a52a2a"><b>:</b></font> splitBy x t<br>
<font color="#2e8b57"><b>where</b></font> (h,rest) <font color="#a52a2a"><b>=</b></font> break (<font color="#a52a2a"><b>==</b></font> x) xs<br>
t <font color="#a52a2a"><b>=</b></font> drop <font color="#ff00ff">1</font> rest<br>
</font>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com7tag:blogger.com,1999:blog-16846333.post-27548780766347728332009-08-27T22:51:00.005-05:002009-08-27T23:01:13.476-05:00Parker Griffith radio interviewU.S. Representative Parker Griffith, whom I've <a href="http://gbacon.blogspot.com/2009/06/dear-congressman-griffith.html">written about before</a> in this space, was <a href="http://a1135.g.akamai.net/f/1135/18227/1h/cchannel.download.akamai.com/18227/podcast/HUNTSVILLE-AL/WBHP-AM/082509.mp3?CPROG=PCAST&MARKET=HUNTSVILLE-AL&NG_FORMAT=newstalk&SITE_ID=1110&STATION_ID=WBHP-AM&PCAST_AUTHOR=WBHP&PCAST_CAT=news/talk&PCAST_TITLE=WBHP%27s_Toni_and_Gary">recently on WBHP</a>.
<p>
I like his positions on the stimulus, bailouts, cap & tax, and healthcare: all no!
<p>
I was happy to hear him speak out against the AMA, which many doctors can't do out of fear of losing their licenses. The AMA cartel is a big source of what's wrong with healthcare in America.
<p>
He was also correct that the so-called reform proposals are really "overreach" and a "power grab," nothing to do with improving health care. In a 1961 speech, <a href="http://www.livevideo.com/video/embedLink/415EE6E634A14E2F828ED104CE605929/262316/ronald-reagan-speaks-out-again.aspx" target="_blank">Ronald Reagan warned</a>, "One of the traditional methods of imposing statism or socialism on a people has been by way of medicine."
<p>
So far so good. But then he got to his solution.
<p>
I understand the poor guy was sleep deprived, but he fell back into the usual feel-good blah-blah-blah about making health insurance companies "play by the same rules." In real life, this will mean more federal oversight, higher prices, less competition, and therefore less consumer satisfaction.
<p>
As a physician, he ought to understand the folly of treating the symptom. The real problem is adults still believe in Santa Claus but use the code name "health insurance." Imagine if State Farm were expected to pony up every time you took your car in for an oil change or other routine maintenance. Health insurance is no such thing: it's really a sort of pre-paid entitlement program, but entirely perverse. For example, legislation requires everyone to pay the same premium in employer-sponsored group insurance. This means healthy people are overcharged, and the couch potato gets a free ride. The system subsidizes and therefore encourages poor health!
<p>
In the market, sellers compete against sellers, but buyers also compete against buyers. Throwing deep-pocketed "insurers" into the mix inevitably drives prices beyond affordable levels, especially given the way "insurance" destroys patient price-sensitivity.
<p>
I like Peter Schiff's proposal much better. Health "insurers" exist only because of aberration in the tax code. This special tax treatment is why open-market consumers can't purchase their products for reasonable prices. Schiff proposes ending this subsidy but simultaneously raising the personal exemption so as to make the change a wash for taxpayers. The true costs of health "insurance" would then be laid bare. The much cheaper option of major-medical policies would become more attractive. Insurers would have to compete with each other on price, terms, service, and so on. We'd no longer be chained to our employer-sponsored plans.
<p>
This would create <i>enormous</i> downward pressure on healthcare prices because people would pay for oil changes.. err, routine doctor visits out of pocket from money that they <i>gasp</i> saved in anticipation of such expenses. Of course when the out-of-pocket limit hits, their <i>bona fide</i> insurance would kick in and cover the rest. Economic arbitrage doing its work means that such a system would also benefit those who opt not to purchase insurance policies.
<p>
The jingoistic breast-beating about money versus commitment was poor cover for the fact that Uncle Sam is drowning in debt and flat-out broke. The feds can barely afford to pay their bills now. How will they afford a new program that will dwarf Social Security and Medicare?Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com4tag:blogger.com,1999:blog-16846333.post-31769588305882447452009-08-24T21:16:00.009-05:002009-09-09T12:56:09.311-05:00Press hitA good friend of mine rated a mention in a <a href="http://online.wsj.com/article/SB10001424052970203706604574370913934722486.html">Wall Street Journal article about blatant bias in Heisman voting</a>:
<blockquote>"It seems like it's always something with us," says Patrick Bobo, a Tennessee fan who contributes to a site called <a href="http://www.3sib.com/">Third Saturday in Blogtober</a>. "A lot of Tennessee fans say they don't want the stupid award because it's a joke."</blockquote>
(Back in college, he wore FSU gear but then started pulling for the Vols when they did so well under Peyton Manning, thus earning plenty of good-natured ribbing about bandwagon-hopping.)
<p>
<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix-fvQdIQs1tP7bhK9wFEgm0TFEnVWCbbtPN_dg_reLYCAF5Ft6H-LcBe_uivib89h43UpdbG-Rk33ebumklVMqb8MecOeGyMcOnhSTu_OX6yP8fYqm2kXIZWPFPs-yueaH2eDxA/s1600-h/rockystopMini.jpg"><img style="float:left; margin:0 10px 10px 0;cursor:pointer; cursor:hand;width: 290px; height: 225px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix-fvQdIQs1tP7bhK9wFEgm0TFEnVWCbbtPN_dg_reLYCAF5Ft6H-LcBe_uivib89h43UpdbG-Rk33ebumklVMqb8MecOeGyMcOnhSTu_OX6yP8fYqm2kXIZWPFPs-yueaH2eDxA/s320/rockystopMini.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5373725023988760066" /></a>
<p>
As Darren Everson notes in "The South's Heisman Trophy Grudge," no Crimson Tide player has ever won the Heisman even though the program is one of the all-time elites in college football. Bobo pulls for the wrong team but is right on about what a joke Heisman voting is.
<p>
The name of the blog is a nod to <a href="http://en.wikipedia.org/wiki/Third_Saturday_in_October">the third Saturday in October</a>, the annual renewal of the big Alabama-Tennessee rivalry—which happens to take place on the fourth Saturday in October of this year, but whatever. Bloggers from both sides fuel the fire with some good ol' trash-talk.
<p>
Even people outside the South know of the Alabama-Auburn rivalry, but the Vols run a very close second. A few years ago, for example, <a href="http://gbacon.blogspot.com/2007/05/i-seen-it.html">I said I'd rather beat UT than the Tigers</a> if I had to choose. Maybe it has something to do with living in north Alabama and having to endure a higher rate of Tennessee puke-orange sightings. The inset is <a href="http://www.danielmooreart.com/rockystop.html">Daniel Moore's "Rocky Stop,"</a> which depicts Roman Harper's (#41) fumble-causing, game-saving hit in an ugly 6-3 matchup.
<p>
Congratulations, but I'm looking forward to enjoying this year's victory cigar, Bobo!Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-13704610754964784472009-08-18T12:28:00.003-05:002009-08-18T12:53:53.222-05:00We have universal legal careWow, is it awesome too!
<blockquote>
After his appeal had failed and before he was exonerated, Lloyd filed a complaint with the state. He told them Slameka [Lloyd's public defender] never gave him the time of day. Harlin still has a copy of Slameka's rebuttal, which she read out loud:
<blockquote>
“This is a sick individual who raped, kidnapped and strangled a young woman on her way to school. His claim of my wrongdoing is frivolous, just as is his existence. Both should be terminated.”
</blockquote>
When asked if he really thought his own client should be executed, Slameka said yes, that's what he wrote at the time and that's how he felt.
</blockquote>
<a href="http://www.npr.org/templates/story/story.php?storyId=111811319">Read the full story at NPR.</a>
<p>
After having 17 years of his life stolen over a horrible crime that DNA evidence showed he didn't commit, Lloyd got out but died two short years later.
<blockquote>
His sister, Ruth Harlin, says if someone close to her needed a defense lawyer today, she would do whatever it took to pay for a lawyer.
<p>
“I'd mortgage the house,” Harlin says. “I would not let a public defender defend anyone in my family ever again. Ever, ever again.”
</blockquote>
Universal legal care's problems—chronic underfunding, unmanageable caseloads, top talent unwilling to participate in the insanity, poor standard of care, and on and on and on—are built in despite its proponents' good intentions.
<p>
Economics 101: Incentives Matter!Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com3tag:blogger.com,1999:blog-16846333.post-4888375357708758772009-08-16T15:09:00.004-05:002009-08-17T21:36:04.676-05:00Simple analogy for lazy evaluationIn <a href="http://gbacon.blogspot.com/2009/07/mrs-bs-tasty-cooking.html">my talk on Friday</a>, I was explaining <a href="http://en.wikibooks.org/wiki/Haskell/Laziness">Haskell's laziness</a> using the following example:
<pre><span class='definition'>evens</span> <span class='layout'>(</span><span class='keyword'>_</span><span class='conop'>:</span><span class='varid'>x</span><span class='conop'>:</span><span class='varid'>xs</span><span class='layout'>)</span> <span class='keyglyph'>=</span> <span class='varid'>x</span> <span class='conop'>:</span> <span class='varid'>evens</span> <span class='varid'>xs</span></pre>
I used promises and <a href="http://catb.org/jargon/html/T/thunk.html">thunks</a> to show that the recursive application of <code><span class='varid'>evens</span> <span class='varid'>xs</span></code> is not evaluated immediately and that we could define the unbounded list of all positive even numbers with <code> <span class='varid'>evens</span> <span class='keyglyph'>[</span><span class='num'>1</span><span class='keyglyph'>..</span><span class='keyglyph'>]</span></code> without running off into an infinite loop. Some in the mostly imperative-minded audience were still confused.
<p>
Someone asked, “Is it kind of like a recipe?” <a href="http://gbacon.blogspot.com/2009/07/mrs-bs-tasty-cooking.html">Again</a> my wife's oatmeal cream pies found a fun place in Haskell and this time provided a helpful analogy!
<p>
In our pantry we have ingredients such as oatmeal, sugar, and so on. She has her trusty recipe. As long as we provide ingredients and are willing to wait, we can get as many oatmeal cream pies as we want.
<p>
The analogy is imperfect. Diminishing marginal utility doesn't weigh on a CPU's execution of programs, but smiling, appreciative faces and delighted exclamations of "Mmm!"—although powerful—may ultimately need to be augmented with shoe-shopping gift certificates to keep the party going.Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-61284637082310316472009-08-16T14:50:00.005-05:002009-08-16T15:05:28.670-05:00עִמָּנוּאֵלFor a child will be born to us, a son will be given to us;<br/>
And the government will rest on His shoulders;<br/>
And His name will be called Wonderful Counselor, Mighty God,<br/>
Eternal Father, Prince of Peace.
<p>
<a href="http://www.biblegateway.com/passage/?book_id=29&chapter=9&version=49">Isaiah 9:6</a>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-90886617878058279162009-08-10T22:42:00.004-05:002009-08-10T23:54:59.243-05:0010Log10 Tech Seminar: HaskellCome sharpen your skills with a beginner-friendly introduction to Haskell, the advanced functional language that will completely rewire your brain—for the better! I'll give an overview of the language, using the type system to prevent bugs, automatic property-based testing with QuickCheck, and how to improve your procedural or object-oriented code by borrowing from the functional paradigm.
<p>
Join us on Friday, August 14, from 11:30am to 1pm in dB's large conference room:
<blockquote>
deciBel Research, Inc.<br/>
1525 Perimeter Parkway, Suite 500<br/>
Huntsville, Alabama 35806<br/>
Phone: 256-716-0787<br/>
<a href="http://maps.google.com/maps?f=q&source=s_q&hl=en&geocode=&q=1525+Perimeter+Pkwy+NW,+Huntsville,+AL+35806&sll=37.0625,-95.677068&sspn=28.114729,59.150391&ie=UTF8&ll=34.747061,-86.673245&spn=0.007105,0.014441&z=16&iwloc=A">via Google Maps</a>
</blockquote>
RSVP to margie at dbresearch dot net. This is a lunchtime event, so feel free to brownbag it!Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-50025333032627605842009-08-08T11:56:00.003-05:002009-08-08T12:03:12.854-05:00DangerousHis speech was smooth as butter,<br />
yet war was in his heart;<br />
his words were softer than oil,<br />
yet they were drawn swords.
<p>
<a href="http://www.biblegateway.com/passage/?search=Psalm%2055;&version=47;">Psalm 55:21</a>Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com0tag:blogger.com,1999:blog-16846333.post-49669027724580857082009-08-07T21:46:00.003-05:002009-08-08T09:22:59.009-05:00git: shrinking Subversion importAt <tt>$WORK</tt>, we've been attempting for years—but fairly infrequently—to do distributed development with centralized Subversion. We finally had enough and decided to move to git.
<p>
Part of that move involved importing a couple of projects with 6+ years of history. Early revisions carried lots of binary test data, so <a href="http://www.kernel.org/pub/software/scm/git/docs/git-svn.html">git svn</a> clone produced repositories weighing in at 3.5 and 4.5 gigabytes.
<p>
Another less than satisfactory result was the umpteen bazillion git branches corresponding to git tags. Some of the git branches formed families with names of the form <i>name-x.y.z@1234</i>, where <i>name-x.y.z</i> is the name of a Subversion release tag and 1234 was a Subversion revision that modified the tag. A happy design choice made the branch <i>name-x.y.z</i> (with no @<i>nnn</i>) the head revision of that Subversion tag, so we easily picked off some targets:
<pre>$ git branch -r -D `git branch -r | grep @`</pre>
Cribbing from <a href="http://github.com/jcoglan/svn2git/tree/master">svn2git</a>, converting the git branches to git tags was a series of commands of the form
<pre>$ git checkout 1.2.3
$ git tag -a -m "Tagging release 1.2.3" v1.2.3
$ git branch -r -D 1.2.3</pre>
Then to make the Subversion trunk the git master branch:
<pre>$ git branch -D master
$ git checkout trunk
$ git checkout -f -b master
$ git branch -r -D trunk</pre>
Here's a good point to checkpoint your work in case you hose something later.
<p>
Using <a href="http://stubbisms.wordpress.com/2009/07/10/git-script-to-show-largest-pack-objects-and-trim-your-waist-line/">Antony Stubbs's script to find the biggest objects in a repo's packs</a>, we determined that much of the bulk came from huge <a href="http://www.hdfgroup.org/HDF5/">HDF5-format</a> test baselines along with a few others. So we cut them out:
<pre>$ git filter-branch -d /dev/shm/scratch --index-filter \
"git rm --cached -f --ignore-unmatch '*.h5'; \
git rm --cached -f --ignore-unmatch '*.sig'; \
git rm --cached -f --ignore-unmatch '*.2dsc'" \
--tag-name-filter cat -- --all</pre>
The use of <tt>--index-filter</tt> makes the long process (remember, it has to hit all possible revisions) quicker because it operates directly on the index rather than checking out every snapshot, munging the filesystem, and shoving the new snapshot back in. Also, <tt>/dev/shm</tt> is a <a href="http://en.wikipedia.org/wiki/TMPFS">tmpfs</a> mount for better throughput, and the directory named with <tt>-d</tt> shouldn't exist.
<p>
The <tt>git filter-branch</tt> manpage has a <a href="http://www.kernel.org/pub/software/scm/git/docs/git-filter-branch.html#_checklist_for_shrinking_a_repository">checklist for shrinking a repository</a> that recommends running <tt>filter-branch</tt> and then cloning to leave behind the cruft.
<p>Cloning with a filesystem path makes hardlinks, so use a URL:
<pre>$ git clone file:///home/gbacon/src/dBTools.git</pre>
Even after doing this, some big unnamed blobs had survived the clone. Thanks to <a href="irc://irc.freenote.net/git">#git on freenode</a> for the suggestion to excise the <a href="http://www.gitready.com/intermediate/2009/02/09/reflog-your-safety-net.html">reflog</a>:
<pre>$ git reflog expire --verbose --expire=0 --all
$ git gc --prune=0</pre>
Note that these options will require a fairly recent git.
<p>
After all these steps, the git repositories were went from gigabytes to 75 and 100 megabytes, <em>much</em> nicer!Greghttp://www.blogger.com/profile/18339931653885510418noreply@blogger.com4