<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/css" href="/stylesheets/rss.css"?>
<rss version="2.0" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Random Hacks: Bowling in Haskell: A response to Ron Jeffries</title>
    <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell</link>
    <language>en-us</language>
    <ttl>40</ttl>
    <description>Technology and Other Fun Stuff</description>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Tracy Harms</title>
      <description>&lt;p&gt;The verbal description of bonus for strikes is inaccurate. It says the bonus is two balls from &amp;#8220;the next frame&amp;#8221; but in fact it is the pin tally from next two balls, regardless of what frames they are in.&lt;/p&gt;</description>
      <pubDate>Fri, 01 May 2009 23:06:28 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:398ff9e2-1d63-4650-9ad8-ad22611e5bf3</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-613</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Seth Tisue</title>
      <description>&lt;p&gt;Isaac,&lt;/p&gt;


	&lt;p&gt;You write &amp;#8220;How strange that we’re writing scoring programs that don’t have all the information available to people using a bowling scoresheet!&amp;#8221;&lt;/p&gt;


	&lt;p&gt;I don&amp;#8217;t agree that it&amp;#8217;s strange. A bowling scoresheet doesn&amp;#8217;t think for you; you have to know how to use it. If you&amp;#8217;re scoring and you see a player knock down 4 pins, you have to know what box to write the 4 in. The input format you suggest assumes that part of the problem is already solved before your code runs. So of course your code is shorter and simpler!&lt;/p&gt;</description>
      <pubDate>Thu, 08 Jan 2009 17:02:13 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:e05b9089-1b95-479b-a4e5-96454ac6adcf</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-595</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Isaac Gouy</title>
      <description>&lt;p&gt;Talking with Dan Mead, I think he was on the right track.&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s go back to &lt;a href="http://www.xprogramming.com/xpmag/acsBowlingProceduralFrameScore.htm"&gt;the scoresheet used to score bowling games&lt;/a&gt;.&lt;/p&gt;


	&lt;p&gt;The top row, where rolls are recorded, is a 9&amp;#215;2 1&amp;#215;3 template.&lt;/p&gt;


	&lt;p&gt;iirc the examples I&amp;#8217;ve seen don&amp;#8217;t use that template, but extract rolls and ignore implicit information. The examples I&amp;#8217;ve seen use an irregular compressed representation&lt;pre&gt;[10,   10,   10,   10,   10,   10,   10,   10,   10,   10,10,10]&lt;/pre&gt;instead of that regular 9&amp;#215;2 1&amp;#215;3 scoresheet template &lt;pre&gt;[10,0, 10,0, 10,0, 10,0, 10,0, 10,0, 10,0, 10,0, 10,0, 10,10,10]&lt;/pre&gt;&lt;/p&gt;


	&lt;p&gt;How strange that we&amp;#8217;re writing scoring programs that don&amp;#8217;t have all the information available to people using a bowling scoresheet!&lt;/p&gt;


	&lt;p&gt;Let&amp;#8217;s use those 9&amp;#215;2 1&amp;#215;3 scoresheets!&lt;pre&gt;score [r1,r2,r3]     = r1 + r2 + r3

score [r1,r2, b1,b2,b3 :rs]   
   | r1  10
      | b1  10     = 10 &lt;ins&gt; 10 &lt;/ins&gt; b3 + score [b1,b2,b3:rs]
                     = 10 &lt;ins&gt; b1 &lt;/ins&gt; b2 + score [b1,b2,b3:rs]
   | r1 &lt;ins&gt; r2 == 10   = 10 &lt;/ins&gt; b1      + score [b1,b2,b3:rs]
   | otherwise       = r1 &lt;ins&gt; r2      &lt;/ins&gt; score [b1,b2,b3:rs]&lt;/pre&gt;&lt;/p&gt;</description>
      <pubDate>Wed, 16 May 2007 13:50:15 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:5b067d39-1418-4920-9c1f-f481af80a809</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-452</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Isaac Gouy</title>
      <description>&lt;p&gt;iirc all of the bowling game examples assume valid input data (and mostly assume complete games). So in the bowling game examples, the &lt;em&gt;“ten-ness” of the game&lt;/em&gt; is not caused by a need to check for the end of the game, it&amp;#8217;s caused by the need to distinguish bonus rolls from rolls.&lt;/p&gt;
&lt;p&gt;The bonus rolls do not themselves contribute to the score, they are &lt;a href="http://en.wikipedia.org/wiki/Ten-pin_bowling"&gt;only included as part of bonus for some other strike or spare roll&lt;/a&gt;. The difference between bonus rolls and rolls isn&amp;#8217;t captured by &lt;tt&gt;[Int]&lt;/tt&gt; so we have to recover that lost information by frame counting till the tenth frame.&lt;/p&gt;
&lt;p&gt;Represent both bonus rolls and rolls in the data, and the need for frame counting disappears.&lt;/p&gt;&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_clean "&gt;   [
       Roll 10
      ,Roll 5 ,Roll 5 
      ,Roll 10 
      ,Roll 5 ,Roll 5 
      ,Roll 10
      ,Roll 5 ,Roll 5 
      ,Roll 10 
      ,Roll 5 ,Roll 5 
      ,Roll 10 
      ,Roll 5 ,Roll 5 
      ,BonusRoll 10
   ]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here&amp;#8217;s a Clean pattern matching program that will score correct incomplete games and score correct complete games. No doubt it&amp;#8217;s easy to do the same thing in Haskell. It&amp;#8217;s recursive. It just stops based on the data coming to an end. It doesn&amp;#8217;t basically count up to or down from ten.&lt;/p&gt;
&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_clean "&gt;:: R = Roll !Int | BonusRoll !Int

score :: !.[R] -&amp;gt; Int

score []       = 0
score [_]      = 0
score [r1, r2] = if (roll r1 + roll r2 &amp;lt; 10) (roll r1 + roll r2) 0

score [r1, r2, r3 :rs]
   | roll r1 == 10             = roll r1 + bonus r2 + bonus r3 + score [r2,r3:rs]
   | roll r1 + roll r2 == 10   = roll r1 + roll r2 +  bonus r3 + score [r3:rs]
   | otherwise                 = roll r1 + roll r2 +  score [r3:rs]

roll (Roll i) = i
roll (BonusRoll i) = 0

bonus (Roll i) = i
bonus (BonusRoll i) = i&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
      <pubDate>Sat, 12 May 2007 22:16:14 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:378d239d-b273-4f7d-9f62-5c4fe10a4129</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-451</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Eric</title>
      <description>&lt;p&gt;Tom, Chris: Thank you for the interesting solutions!&lt;/p&gt;


	&lt;p&gt;Tom&amp;#8217;s solution is pretty twisted, but it contains lots of crunchy bits of Haskell goodness.&lt;/p&gt;


	&lt;p&gt;Chris&amp;#8217; solution is a bit more practical. In particular, it reports errors, which is vital if you can&amp;#8217;t trust your input.&lt;/p&gt;


	&lt;p&gt;If we&amp;#8217;re going to handle invalid input, it would be desirable to have &amp;#8220;negative&amp;#8221; test cases&amp;#8212;invalid inputs, and the errors they should produce.&lt;/p&gt;</description>
      <pubDate>Mon, 30 Apr 2007 13:36:43 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:b508cb24-2c35-45f4-b10b-a005f2489b10</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-421</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Chris Kuklewicz</title>
      <description>&lt;p&gt;Converting the list of balls to a score is a simplified parsing problem.  I made the intermediate parsed form explicit and I have posted my version of Haskell bowling to &lt;a href="http://haskell.org/haskellwiki/Bowling"&gt;the Haskell wiki&lt;/a&gt; (along with a link to this blog post).&lt;/p&gt;


	&lt;p&gt;My version uses an inferred (StateT [Int] (Either String) Frame) to keep track of the remaining balls while parsing and handle the possibility of encountering bad input.  I ran it through Eric&amp;#8217;s tests above and it passed.  The error checking in my code emphasizes the rules and helps make them &amp;#8220;as clear as possible&amp;#8221;.&lt;/p&gt;


	&lt;p&gt;Since I want to detect errors, a simple (take 10) might have returned fewer than 10 frames. The problem of how to account for exactly 10 frames is handled by using replicateM in the line&lt;/p&gt;


	&lt;pre&gt;&lt;code&gt;frames &amp;lt;- replicateM 10 (StateT parseFrame)&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;The above is purely declarative, and there is no need for me to use any kind of counting parameter or write any comparison tests or increment/decrement anything.&lt;/p&gt;


	&lt;p&gt;As a bonus, the parsed frames are stored in an array and can be decoded by &amp;#8216;toBalls&amp;#8217; into a list of list of pins.&lt;/p&gt;</description>
      <pubDate>Mon, 30 Apr 2007 05:59:20 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:e0a213d9-f758-482f-ba6d-cc2c421f7ade</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-420</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Tom Moertel</title>
      <description>&lt;p&gt;Eric,&lt;/p&gt;


	&lt;p&gt;Back when Mr. Jeffries first posted his article about the Bowling Game, I had a rather lengthy email correspondence with him, during which I attempted to argue against his claim that the &amp;#8220;recursive style&amp;#8221; fosters programming mistakes such as failing to account for ten-ness in the Bowling Game.  I tried to show that iteration and recursion were actually equivalent and that you could  even solve the problem without using either. To demonstrate the last point, I sent him a new version of &lt;a href="http://blog.moertel.com/articles/2006/04/05/the-bowling-game-kata-in-haskell"&gt;my earlier, somewhat-golfed solution&lt;/a&gt;. The new version had an interesting way of accounting for ten-ness, which I&amp;#8217;ll post below in hopes you find it amusing:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-comment'&gt;-- compute score of a full game of bowling&lt;/span&gt;

&lt;span class='hs-definition'&gt;score2&lt;/span&gt; &lt;span class='hs-varid'&gt;rs&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;
    &lt;span class='hs-varid'&gt;fst&lt;/span&gt; &lt;span class='hs-varop'&gt;.&lt;/span&gt; &lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt;&lt;span class='hs-varop'&gt;.&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt; &lt;span class='hs-varop'&gt;$&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-num'&gt;0&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;rs&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;
  &lt;span class='hs-keyword'&gt;where&lt;/span&gt;
    &lt;span class='hs-varid'&gt;s&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varid'&gt;uncurry&lt;/span&gt; &lt;span class='hs-varid'&gt;sc2&lt;/span&gt; 

&lt;span class='hs-comment'&gt;-- consume and score 1 frame from 'rs', accumulating score in 's'&lt;/span&gt;

&lt;span class='hs-definition'&gt;sc2&lt;/span&gt; &lt;span class='hs-varid'&gt;s&lt;/span&gt; &lt;span class='hs-varid'&gt;rs&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-keyword'&gt;case&lt;/span&gt; &lt;span class='hs-varid'&gt;rs&lt;/span&gt; &lt;span class='hs-keyword'&gt;of&lt;/span&gt;
    &lt;span class='hs-num'&gt;10&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;rs'&lt;/span&gt;                &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;sc'&lt;/span&gt; &lt;span class='hs-num'&gt;3&lt;/span&gt; &lt;span class='hs-varid'&gt;rs'&lt;/span&gt;
    &lt;span class='hs-varid'&gt;x&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;y&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;rs'&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;|&lt;/span&gt; &lt;span class='hs-varid'&gt;x&lt;/span&gt; &lt;span class='hs-varop'&gt;+&lt;/span&gt; &lt;span class='hs-varid'&gt;y&lt;/span&gt; &lt;span class='hs-varop'&gt;==&lt;/span&gt; &lt;span class='hs-num'&gt;10&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;sc'&lt;/span&gt; &lt;span class='hs-num'&gt;3&lt;/span&gt; &lt;span class='hs-varid'&gt;rs'&lt;/span&gt;
            &lt;span class='hs-keyglyph'&gt;|&lt;/span&gt; &lt;span class='hs-varid'&gt;otherwise&lt;/span&gt;   &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;sc'&lt;/span&gt; &lt;span class='hs-num'&gt;2&lt;/span&gt; &lt;span class='hs-varid'&gt;rs'&lt;/span&gt;
    &lt;span class='hs-keyword'&gt;_&lt;/span&gt;                     &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-varid'&gt;error&lt;/span&gt; &lt;span class='hs-str'&gt;"ill-formed sequence of rolls"&lt;/span&gt;
  &lt;span class='hs-keyword'&gt;where&lt;/span&gt;
    &lt;span class='hs-varid'&gt;sc'&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-varid'&gt;rs'&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;s&lt;/span&gt; &lt;span class='hs-varop'&gt;+&lt;/span&gt; &lt;span class='hs-varid'&gt;sum&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;take&lt;/span&gt; &lt;span class='hs-varid'&gt;n&lt;/span&gt; &lt;span class='hs-varid'&gt;rs&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;rs'&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;Cheers,&lt;br/&gt;
Tom&lt;/p&gt;</description>
      <pubDate>Sun, 29 Apr 2007 21:53:34 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:6f199821-d8d0-44aa-9736-f9d019ac3a26</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-419</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Eric</title>
      <description>&lt;p&gt;Thanks, dmead, for inspiring this article!&lt;/p&gt;


	&lt;p&gt;I think Jeffries was right when he said that:&lt;/p&gt;


&lt;blockquote&gt;A game of bowling consists of ten frames, not less or more, and the “ten-ness” of the game is not represented in the recursive solutions at all.&lt;/blockquote&gt;

	&lt;p&gt;While I&amp;#8217;m sure it&amp;#8217;s possible to write a (correct) recursive bowling program that doesn&amp;#8217;t mention the number 10, you would have to add more complexity to &lt;code&gt;scoreFrame&lt;/code&gt;, or add sentinel values at the end of the game.&lt;/p&gt;


	&lt;p&gt;So that&amp;#8217;s why I went with &lt;code&gt;take 10&lt;/code&gt;&amp;mdash;it&amp;#8217;s the shortest way to build &amp;#8220;ten-ness&amp;#8221; into the program, and it keeps any trickiness out of &lt;code&gt;scoreFrame&lt;/code&gt; or &lt;code&gt;reduce&lt;/code&gt;. Also, it&amp;#8217;s better karma. ;-)&lt;/p&gt;


	&lt;p&gt;Other Dan: Thanks for pointing out &lt;code&gt;unfoldr&lt;/code&gt;! I don&amp;#8217;t always think of it when I should.&lt;/p&gt;


	&lt;p&gt;In production code, it&amp;#8217;s probably better to define &lt;code&gt;reduce&lt;/code&gt; in terms of &lt;code&gt;unfoldr&lt;/code&gt; (or &lt;code&gt;build&lt;/code&gt;?), if only so we get access to &lt;a href="http://www.randomhacks.net/articles/2007/02/10/map-fusion-and-haskell-performance"&gt;fusion&lt;/a&gt;.&lt;/p&gt;</description>
      <pubDate>Sun, 29 Apr 2007 09:44:49 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:2332bedd-c5ef-4895-9565-a7e7128c2bc8</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-416</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by dmead</title>
      <description>&lt;p&gt;hey&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;m the Dan Mead he wrote about in the original bowling article&lt;/p&gt;


	&lt;p&gt;I actually wrote another implementation which we debated over email for a few weeks (similar to this, but has the same bugs as the first version). Ron seems very adamant that FP techniques are exactly the same as &lt;span class="caps"&gt;OOD&lt;/span&gt; design and theres no point in investigating recursion and all that jazz.&lt;/p&gt;


	&lt;p&gt;I&amp;#8217;d like to see if someone can some up with a recursive solution that doesn&amp;#8217;t use a counter or have the problems my version did&lt;/p&gt;


	&lt;p&gt;that would be quite impressive :)&lt;/p&gt;</description>
      <pubDate>Sun, 29 Apr 2007 03:34:50 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:e3a23c51-c800-48ee-91ec-b1ec457dcf5b</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-415</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by lsb</title>
      <description>&lt;p&gt;reduce looks kind of hairy; why not &amp;#8220;iterate (snd . scoreGame)&amp;#8221; ?&lt;/p&gt;</description>
      <pubDate>Sat, 28 Apr 2007 20:49:48 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:3a8d86a4-fd92-4b12-b152-dfeb6f147b78</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-414</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Dan</title>
      <description>&lt;p&gt;As it happens, reduce is in the standard library, although its type is somewhat disguised. The function is:&lt;/p&gt;


&lt;pre&gt;unfoldr :: (a -&amp;gt; Maybe (b, a)) -&amp;gt; a -&amp;gt; [b]&lt;/pre&gt;

	&lt;p&gt;Of course, scoreFrame doesn&amp;#8217;t wrap its results in Maybe, and in fact, many of the standard functions that would be useful with unfoldr (splitAt, divMod&amp;#8230;) don&amp;#8217;t either. However, we can write a function to augment these with a stopping predicate:&lt;/p&gt;


&lt;pre&gt;stopOn :: (a -&amp;gt; Bool) -&amp;gt; (a -&amp;gt; b) -&amp;gt; a -&amp;gt; Maybe b
stopOn p f a =
  if p a
    then Nothing
    else Just (f a)&lt;/pre&gt;

	&lt;p&gt;Now, scoreGame becomes:&lt;/p&gt;


&lt;pre&gt;scoreGame balls =
  sum . take 10
    $ unfoldr (stopOn null scoreFrame) balls&lt;/pre&gt;

	&lt;p&gt;Of course, defining stopOn is just about as much work as defining reduce, so I suppose it&amp;#8217;s a bit of a wash. It might be handy if stopOn were in the standard library for just such an occasion (although stopOn probably isn&amp;#8217;t the best name, but I haven&amp;#8217;t thought of a better one yet; my initial thought was &amp;#8216;unless&amp;#8217;, but that&amp;#8217;s taken already), but to my knowledge, it isn&amp;#8217;t.&lt;/p&gt;


	&lt;p&gt;(Apologies for the code formatting. I couldn&amp;#8217;t figure out which tag to use to get it to come out like yours (and the code tags were causing line wrapping).)&lt;/p&gt;</description>
      <pubDate>Sat, 28 Apr 2007 20:16:41 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:39d79cfe-ece2-4d9b-8fda-929d51a94685</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-413</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Eric</title>
      <description>&lt;p&gt;Jeffries actually had a very good point, regarding the lack of &amp;#8220;ten-ness&amp;#8221; in the earlier Haskell solutions.&lt;/p&gt;


	&lt;p&gt;In particular, he described &lt;a href="http://www.xprogramming.com/xpmag/dbcRecurringDrama.htm"&gt;two test cases&lt;/a&gt; that break the first Haskell implementation:&lt;/p&gt;


&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;gutter&lt;/span&gt; &lt;span class='hs-num'&gt;16&lt;/span&gt;&lt;span class='hs-varop'&gt;++&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-num'&gt;0&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-num'&gt;0&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-num'&gt;10&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-num'&gt;2&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-num'&gt;3&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-num'&gt;15&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;
&lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;gutter&lt;/span&gt; &lt;span class='hs-num'&gt;16&lt;/span&gt;&lt;span class='hs-varop'&gt;++&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-num'&gt;10&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;  &lt;span class='hs-num'&gt;2&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;&lt;span class='hs-num'&gt;3&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;    &lt;span class='hs-num'&gt;20&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

	&lt;p&gt;If you&amp;#8217;re processing frames recursively (with no frame counter), you can&amp;#8217;t tell these two cases apart. In my version, I  use &lt;code&gt;take 10&lt;/code&gt; to ensure that the program processes exactly 10 frames.&lt;/p&gt;


	&lt;p&gt;All in all, I&amp;#8217;m quite fond of &lt;span class="caps"&gt;TDD&lt;/span&gt;. At least for certain problems, it&amp;#8217;s a big win. But other problems, it&amp;#8217;s better to just go for a walk and think a bit.&lt;/p&gt;</description>
      <pubDate>Sat, 28 Apr 2007 19:07:28 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:aa434cf8-e852-4f24-bcc1-e459ef1f9809</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-412</link>
    </item>
    <item>
      <title>"Bowling in Haskell: A response to Ron Jeffries" by Tony Morris</title>
      <description>&lt;p&gt;You make an interesting final point. I hadn&amp;#8217;t read the article you refer to but the refutation re: Haskell (ten-ness) is really quite amateur and a failing to understand some simple type systems.&lt;/p&gt;


	&lt;p&gt;Your final point refers to your ability to perform an accurate thought experiment (design and write the code) without using &lt;span class="caps"&gt;TDD&lt;/span&gt;. I have long conjectured that these hyperbolic development processes (TDD, XP, etc.) exist &lt;strong&gt;entirely&lt;/strong&gt; to make up for one&amp;#8217;s lack of spatial cognitive abilities.&lt;/p&gt;


	&lt;p&gt;Clearly, your abilities exceed the minimal requirement for writing this particular application and a &lt;span class="caps"&gt;TDD&lt;/span&gt; zealot might frown, unable to comprehend this fact.&lt;/p&gt;


	&lt;p&gt;Keep up the good work.&lt;/p&gt;</description>
      <pubDate>Sat, 28 Apr 2007 17:09:11 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:c1bc4a70-caef-4f04-8630-b102c697fa58</guid>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell#comment-411</link>
    </item>
    <item>
      <title>Bowling in Haskell: A response to Ron Jeffries</title>
      <description>&lt;p&gt;Bowling is a &lt;a href="http://en.wikipedia.org/wiki/Ten-pin_bowling#Scoring"&gt;tricky game to score&lt;/a&gt;.  It&amp;#8217;s just complicated enough
to act as a good programming exercise.  And Ron Jeffries has performed this
exercise many times, in &lt;a href="http://www.xprogramming.com/xpmag/acsBowling.htm" title="Adventures in C#: The Bowling Game"&gt;C#&lt;/a&gt;, &lt;a href="http://www.xprogramming.com/xpmag/BowlingForSmalltalkII.htm" title="DBC: Bowling For Smalltalk II"&gt;Smalltalk&lt;/a&gt;, and &lt;a href="http://www.google.com/search?q=+site:www.xprogramming.com+jeffries+bowling" title="More bowling"&gt;other
languages&lt;/a&gt;.  He&amp;#8217;s been searching for a tidy and elegant solution, one
which makes the rules of bowling as clear as possible.&lt;/p&gt;

&lt;p&gt;In the past, though, Jeffries has been a bit skeptical of &lt;a href="http://www.xprogramming.com/xpmag/dbcHaskellBowling.htm" title="Haskell Bowling"&gt;Haskell
implementations of bowling&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;The recursive [Haskell] solution, however, is questionable on
more fundamental grounds. A game of bowling consists of ten frames, not
less or more, and the &amp;#8220;ten-ness&amp;#8221; of the game is not represented in the
recursive solutions at all. Even if we let that slide, the recursive
solutions make it a bit hard to understand what&amp;#8217;s going on.&lt;/blockquote&gt;

&lt;p&gt;Let&amp;#8217;s see if we can do better.  No knowledge of bowling is required&amp;#8211;if we
do this right, our program should be at least as clear as an
&lt;a href="http://en.wikipedia.org/wiki/Ten-pin_bowling#Scoring"&gt;English-language version of the rules&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Along the way, we&amp;#8217;ll encounter lazy lists, an interesting recursion combinator, and &lt;a href="http://www.haskell.org/hoogle/"&gt;Hoogle&lt;/a&gt;, the Haskell search engine.&lt;/p&gt;

&lt;h3&gt;The rules of bowling&lt;/h3&gt;

&lt;p&gt;In bowling, we roll balls down a lane, trying to knock down pins.  If we
know how many pins we knock down with each ball, we can compute the final
score.  So our program looks something like this:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-comment'&gt;-- Pins knocked down by each ball.&lt;/span&gt;
&lt;span class='hs-keyword'&gt;type&lt;/span&gt; &lt;span class='hs-conid'&gt;Balls&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;[&lt;/span&gt;&lt;span class='hs-conid'&gt;Int&lt;/span&gt;&lt;span class='hs-keyglyph'&gt;]&lt;/span&gt;

&lt;span class='hs-comment'&gt;-- Number of points scored.&lt;/span&gt;
&lt;span class='hs-keyword'&gt;type&lt;/span&gt; &lt;span class='hs-conid'&gt;Score&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-conid'&gt;Int&lt;/span&gt;

&lt;span class='hs-definition'&gt;scoreGame&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Balls&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-conid'&gt;Score&lt;/span&gt;
&lt;span class='hs-definition'&gt;scoreGame&lt;/span&gt; &lt;span class='hs-varid'&gt;balls&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt; &lt;span class='hs-varop'&gt;???&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;But how do we implement &lt;code&gt;scoreGame&lt;/code&gt;?&lt;/p&gt;

&lt;h3&gt;Scoring a frame&lt;/h3&gt;

&lt;p&gt;A bowling game is divided into 10 &lt;b&gt;frames&lt;/b&gt;.  Ordinary frames consist of 1 or 2 balls. The 10th frame may have an additional 1 or 2 bonus balls, which we discuss below.&lt;/p&gt;

&lt;p&gt;To score an individual frame, we need to do two things: (1) calculate the score for our frame, and (2) figure out where the next frame
starts.  Our scoring function will return both pieces of information:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-comment'&gt;-- Score one frame and return the rest.&lt;/span&gt;
&lt;span class='hs-definition'&gt;scoreFrame&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;::&lt;/span&gt; &lt;span class='hs-conid'&gt;Balls&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;-&amp;gt;&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-conid'&gt;Score&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-conid'&gt;Balls&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we knock down all 10 pins with the first ball in a frame
(&lt;code&gt;x1&lt;/code&gt;), we call it a &lt;b&gt;strike&lt;/b&gt;, and move on to the next
frame immediately.  But we also get a bonus&amp;#8212;we&amp;#8217;re allowed to count balls
&lt;code&gt;y1&lt;/code&gt; and &lt;code&gt;y2&lt;/code&gt; from the &lt;i&gt;next&lt;/i&gt; frame towards
&lt;i&gt;this&lt;/i&gt; frame&amp;#8217;s score:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-definition'&gt;scoreFrame&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;    &lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;y2&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;|&lt;/span&gt; &lt;span class='hs-varid'&gt;x1&lt;/span&gt; &lt;span class='hs-varop'&gt;==&lt;/span&gt; &lt;span class='hs-num'&gt;10&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;
  &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;y2&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;y2&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;  &lt;span class='hs-comment'&gt;-- Strike&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we knock down all the pins using &lt;i&gt;two&lt;/i&gt; balls (&lt;code&gt;x1&lt;/code&gt; and
&lt;code&gt;x2&lt;/code&gt;), we call it a &lt;b&gt;spare&lt;/b&gt;.  And we get to count one ball from
the next frame as our bonus:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-definition'&gt;scoreFrame&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;x2&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt; &lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;|&lt;/span&gt; &lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;x2&lt;/span&gt; &lt;span class='hs-varop'&gt;==&lt;/span&gt; &lt;span class='hs-num'&gt;10&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;
  &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;x2&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt; &lt;span class='hs-varid'&gt;y1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;     &lt;span class='hs-comment'&gt;-- Spare&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we don&amp;#8217;t manage to knock all 10 pins with two balls, we call it an &lt;b&gt;open
frame&lt;/b&gt;.  And we don&amp;#8217;t get any bonus:&lt;/p&gt;

&lt;div class="typocode"&gt;&lt;pre&gt;&lt;code class="typocode_haskell "&gt;&lt;span class='hs-definition'&gt;scoreFrame&lt;/span&gt; &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt;&lt;span class='hs-varid'&gt;x2&lt;/span&gt;&lt;span class='hs-conop'&gt;:&lt;/span&gt; &lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt; &lt;span class='hs-keyglyph'&gt;=&lt;/span&gt;
  &lt;span class='hs-layout'&gt;(&lt;/span&gt;&lt;span class='hs-varid'&gt;x1&lt;/span&gt;&lt;span class='hs-varop'&gt;+&lt;/span&gt;&lt;span class='hs-varid'&gt;x2&lt;/span&gt;&lt;span class='hs-layout'&gt;,&lt;/span&gt;    &lt;span class='hs-varid'&gt;ys&lt;/span&gt;&lt;span class='hs-layout'&gt;)&lt;/span&gt;        &lt;span class='hs-comment'&gt;-- Open frame&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What happens if we have a strike or a spare in the 10th frame?
We get to roll our bonus balls anyway.  Conventionally, these extra balls
are recorded as part of the 10th frame (making it 3 balls long), but
they&amp;#8217;re really just phantom balls hanging off the end of the game.&lt;/p&gt;

&lt;p&gt;Next, we need to turn &lt;code&gt;scoreFrame&lt;/code&gt; into a recursive function.&lt;/p&gt;&lt;p&gt;&lt;a href="http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell"&gt;Read More&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Sat, 28 Apr 2007 11:53:00 +0000</pubDate>
      <guid isPermaLink="false">urn:uuid:bdc382f2-6bcf-40f0-93ca-54c2b4de03c9</guid>
      <author>Eric Kidd</author>
      <link>http://www.randomhacks.net/articles/2007/04/28/bowling-in-haskell</link>
      <category>Haskell</category>
      <trackback:ping>http://www.randomhacks.net/articles/trackback/409</trackback:ping>
    </item>
  </channel>
</rss>
