<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-2564777502681463717</id><updated>2011-11-08T13:07:54.581-05:00</updated><category term='computational thinking'/><category term='creativity'/><category term='Haskell'/><category term='Ada'/><category term='math'/><category term='TradeMaximizer'/><category term='induction'/><category term='food'/><category term='programming'/><category term='functional programming'/><category term='tournament'/><category term='games'/><category term='crazy types'/><category term='failure'/><category term='rant'/><category term='teaching'/><category term='algorithm in pictures'/><category term='kids'/><category term='recursion'/><title type='text'>Teaching, Playing, and Programming</title><subtitle type='html'></subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>33</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5344797361056783622</id><published>2011-11-06T14:41:00.003-05:00</published><updated>2011-11-06T14:55:16.423-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>On the Dangers of Giving Games as Wedding PresentsorWell, it seemed like a good idea at the time...</title><content type='html'>[&lt;i&gt;This is a letter I included with a recent wedding present.&lt;/i&gt;]

&lt;p&gt;Dear Ben and Sarah,&lt;/p&gt;
&lt;p&gt;Well, it seemed like a good idea at the time…&lt;/p&gt;
&lt;p&gt;I think you’ll enjoy this game, &lt;i&gt;Thunderstone&lt;/i&gt;.  I’ve been playing it a lot with my son.  Like &lt;i&gt;Race for the Galaxy&lt;/i&gt;, this one works very well with two players, but can also handle more players.  (Predictably, with more players, it becomes very chaotic, especially when thieves are in play…)  I’m so certain you’ll enjoy it that I also got you the first expansion, &lt;i&gt;Wrath of the Elements&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;You might notice that this box is the &lt;i&gt;Wrath of the Elements&lt;/i&gt; box.  See, the first &lt;i&gt;Thunderstone&lt;/i&gt; comes with a huge box, with lots of wasted space.  That box is twice as big as this one, and only comes with about half the cards you see before you.  Knowing that dealing with the larger box would be difficult for you, I’ve combined all the cards for both the main game and the expansion into this one box.  (By the way, if you end up liking the game, this box will also easily hold the cards for the second expansion, &lt;i&gt;Doomgate Legion&lt;/i&gt;.)&lt;/p&gt;
&lt;p&gt;There was just one eensy teensy flaw with my plan.  A minor thing really, hardly worth mentioning.&lt;/p&gt;
&lt;p&gt;The original rulebook was too big for this box.&lt;/p&gt;
&lt;p&gt;I considered several options:  Just leave out the rulebook and point you to the &lt;a href="http://www.alderac.com/thunderstonerules.pdf"&gt;online rules&lt;/a&gt;.  Stick the rulebook in a separate, sturdy envelope, which is guaranteed to get lost in about 13.8 nanoseconds.  Fold the rulebook in half and jam it in the box.  Then I found the perfect solution.  A post on BoardGameGeek described trimming the top and bottom off the rulebook—which is all wasted space anyway—with a paper cutter.&lt;/p&gt;&lt;p style="border: solid thin black"&gt;&lt;b&gt;Fun With Words&lt;/b&gt;  Did you know that a &lt;i&gt;mangle&lt;/i&gt; was a British machine used in the 1800’s to press water out of clothes?  It’s called a &lt;i&gt;wringer&lt;/i&gt; in the US.  A probably apocryphal story asserts that the word mangle came into the English language to describe the damage done to clothes by this machine, but I think the causal chain is more likely to run in the other direction, with the machine being named after the word.&lt;/p&gt;&lt;p&gt;Umm, where was I?  Oh yes, paper cutter. &lt;/p&gt;
&lt;p&gt;Anyway, so I bring the rulebook into school and take it over to the room with the paper cutter.  I line it up carefully, and pull down the chopper…which cuts about an inch into the rulebook and sticks.    I push down a little harder…and the entire back of the paper cutter lifts off the table, the chopper twists the rulebook and pulls it partway off the bed and…&lt;/p&gt;
&lt;p&gt;Hey, have you ever had a jam in a paper shredder?  And cleared it by pulling half shredded paper back out the top of the machine.  The papers come out looking pristine partway down the page, and then at a certain line of demarcation (&lt;i&gt;you know, that line really ought to have a cool name, like the Maginot Line or the Mendoza Line&lt;/i&gt;), the rest comes out drooping in sad, wrinkled tatters.  What’s the word?  Oh yeah, mangled.  Why do I bring that up?  No reason, really.&lt;/p&gt;
&lt;p&gt;Hmm, where was I?  Right, paper cutter!&lt;/p&gt;
&lt;p&gt;So I lift up the chopper and pull the rulebook out and…let’s just say it’s not looking too good.  I flip it over—the rulebook, not the paper cutter, although that might have worked better—and try again on the other side.  Let’s just say that &lt;i&gt;that&lt;/i&gt; side left me longing for the Golden Age epitomized by the results of the first side.    A few more minutes, and a few muttered imprecations later, and… &lt;/p&gt;
&lt;p&gt;You know, my wife use to do scrapbooking, and they sell these funny little scissors that are designed to make an artistic ragged edge.  Expensive little buggers.  If only I had known, I could have saved her a lot of money.&lt;/p&gt;
&lt;p&gt;So…&lt;i&gt;Thunderstone&lt;/i&gt;!  Great game!  I think you’re going to like it.  [&lt;i&gt;a few personal comments deleted&lt;/i&gt;]&lt;/p&gt;
&lt;p&gt;Congratulations!&lt;/p&gt;
&lt;p&gt;Chris&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5344797361056783622?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5344797361056783622/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5344797361056783622' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5344797361056783622'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5344797361056783622'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2011/11/on-dangers-of-giving-games-as-wedding.html' title='On the Dangers of Giving Games as Wedding Presents&lt;br&gt;or&lt;br&gt;Well, it seemed like a good idea at the time...'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-717311987727430003</id><published>2010-07-18T03:46:00.002-04:00</published><updated>2010-07-19T06:03:37.964-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='food'/><title type='text'>Eating My Way Across Oahu</title><content type='html'>&lt;p&gt;See also &lt;a href="http://okasaki.blogspot.com/2010/07/eating-my-way-across-kauai.html"&gt;Eating My Way Across Kauai&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New for &lt;i&gt;Lost&lt;/i&gt; fans: see extra links at the end of the post&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;We had fewer days on Oahu than Kauai, and part of that time was spent visiting family, so we had a lot fewer meals out on Oahu.  But, on our last full day, we went on the &lt;a href ="http://hawaiifoodtours.com/hitw.html"&gt;Hole-In-The-Wall&lt;/a&gt; food tour of Honolulu with &lt;a href="http://hawaiifoodtours.com/"&gt;Hawaii Food Tours&lt;/a&gt;.  I've been on several really good food tours around New York, but this blew them all away.  I &lt;b&gt;highly&lt;/b&gt; recommend taking the tour if you ever get the chance.&lt;/p&gt;
&lt;p&gt;Also, the title above is misleading, because all but one of the places reviewed below were in Honolulu.&lt;/p&gt;
&lt;h3&gt;Mochi&lt;/h3&gt;
&lt;p&gt;As a kid, one of my favorite treats was when my father picked up mochi from &lt;a href="http://www.fugetsu-do.com/"&gt;Fugetsu-Do&lt;/a&gt; in the Little Tokyo area of Los Angeles.  Unfortunately, New York offers nothing comparable.  (I've found several places that offer various kinds of manju, but not the kind I grew up with.)&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://jakebrattain.com/LA-6-20-09.php"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEDImkPaFRI/AAAAAAAAADA/7TD1v1-O0jU/s320/mochi-with-red-bean.jpg" border="0" alt="Mochi (photo by Jake Battrain)" id="BLOGGER_PHOTO_ID_5494612110280889618" /&gt;&lt;/a&gt;What is mochi?  The kind I'm talking about is a sweet, sticky, soft, smooth rice dough, usually wrapped around a sweet red or white bean filling.&lt;/p&gt;
&lt;p&gt;In planning our trip, I found several mochi stores in Honolulu that I knew we had to try.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/mikawaya-confectionery-honolulu"&gt;Mikawaya Confectionary&lt;/b&gt;&lt;/a&gt; (inside the Shirokaya department store in Ala Moana Center): We bought four pieces and split them.  The hits were &lt;i&gt;orange gyohi&lt;/i&gt; (an unfilled orange-flavored piece that tasted a bit like a creamsicle), and &lt;i&gt;taro gyohi&lt;/i&gt; (a purple piece with taro-flavoring in the outer dough).&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/hEmwcibuecBV8W7YOCXJ0A?select=Cy1PV2TdYeDFA16mUOlr3Q"&gt;&lt;img style="margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_HOXl0OgNHo0/TEDQyik3u0I/AAAAAAAAADI/KvuQwgYAAa4/s200/l.jpeg" border="0" alt="Orange Gyohi (photo by Steph L.)" id="BLOGGER_PHOTO_ID_5494621112085494594" /&gt;&lt;/a&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/hEmwcibuecBV8W7YOCXJ0A?select=WrhQ6SyHlhfm5EOYTxPAng"&gt;&lt;img style="margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 200px; height: 150px;" src="http://4.bp.blogspot.com/_HOXl0OgNHo0/TEDRtaEAFGI/AAAAAAAAADQ/mybt7gKp9W0/s200/l-1.jpeg" border="0" alt="Taro Gyohi (photo by Steph L.)" id="BLOGGER_PHOTO_ID_5494622123412427874" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/fujiya-limited-honolulu"&gt;Fujiya Limited&lt;/a&gt;&lt;/b&gt; (hard to spot store on Waikamilo Road): The specialty here is fruit mochi.  I was expecting some kind of fruit paste, but no, it's whole pieces of fruit wrapped inside the dough along with a little bit of bean paste.  We had strawberry, blueberry, and raspberry.  (I also snuck in a &lt;i&gt;tsumami&lt;/i&gt;, which was the closest I've had to the ones I grew up with, but softer.)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nisshodo Candy Store&lt;/b&gt;: The hardest of the three to find, it's literally in a warehouse behind a strip mall.  Unfortunately, it was by far the worst of the three, so don't bother.  My beloved white bean filling was particularly bad.&lt;/p&gt;
&lt;h3&gt;Other Sweets&lt;/h3&gt;
&lt;p&gt;I usually tend more to the savory side, but the rest of my family shares a profound sweet tooth.  Hence, many of our stops involved sweets, even beyond the mochi above.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEEHqJK_JtI/AAAAAAAAADY/rs-sM_WXwf8/s1600/l.jpeg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 282px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEEHqJK_JtI/AAAAAAAAADY/rs-sM_WXwf8/s320/l.jpeg" border="0" alt="Coco Puffs (photo by )" id="BLOGGER_PHOTO_ID_5494681440966616786" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/liliha-bakery-honolulu-2"&gt;Liliha Bakery&lt;/a&gt;&lt;/b&gt; (N Kuakini St, just a little off Liliha St): Two words&amp;#8210;&lt;b&gt;coco puffs&lt;/b&gt;.  They sell over 5000 of these puppies a day.  Basically an oversize cream puff with a creamy chocolate filling and a cap of chantilly frosting.  How good are they?  We went to the bakery four times, including three times in less than 24 hours!  Interesting tidbit: The tiny little diner attached to this bakery is where they shot the scene in &lt;i&gt;Lost&lt;/i&gt; where Kate visited her mother.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/7bJ83Jb_DTAF0eOw8j9fow?select=EHEBFLahVpcINwfhx-Gcuw"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEF1fNmpAWI/AAAAAAAAADg/Whajr4zaK5c/s320/l.jpeg" border="0" alt="Malasada (photo by Lina O.)" id="BLOGGER_PHOTO_ID_5494802199456842082" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/leonards-bakery-honolulu"&gt;Leonard's Bakery&lt;/a&gt;&lt;/b&gt; (Kapahalu and Charles): It's all about the &lt;i&gt;malasadas&lt;/i&gt; (Portuguese doughnuts).  Fried dough, more bread-like than ordinary doughnuts, with hints of Portuguese sweet bread.  Always served warm.  Covered in your choice of several different powders (I took the classic sugar, but wish I had tried the li hing). Available with several different fillings (I chose haupia), or without.  If you're into sweet fried dough&amp;#8210;you know who you are!&amp;#8210;this is probably a must try.  I'm not, so I thought it was merely good.  However, more people on our food tour picked this as their favorite stop than any other single place.  Given the quality of the other places we stopped, Leonard's must be doing something right.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/iq5trScNb57AMWf8y5vKGQ?select=mEOYOfl6CPAXsa1tw8HWLg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEHLjGGxX7I/AAAAAAAAADo/FRSMF0RJT8U/s320/l-1.jpeg" border="0" alt="Coconut tarts (photo by Mark G.)" id="BLOGGER_PHOTO_ID_5494896824163590066" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/rainbow-tea-stop-and-bakery-honolulu"&gt;Rainbow Tea Stop&lt;/a&gt;&lt;/b&gt; (Maunakea Marketplace): Very good coconut tarts, but then we tried their &lt;i&gt;banana lumpia&lt;/i&gt;.  Bananas fried in lumpia wrappers, with a carmelized coating.  Out of this world.  And I don't even like bananas!&lt;/p&gt;
&lt;p&gt;While I'm talking about sweets, I should say a few words about &lt;i&gt;haupia&lt;/i&gt;, a kind of coconut pudding.   Imagine coconut-milk jello not quite as firm as finger jello and you'll be on the right track.  Haupia is everywhere in Hawaii, either by itself or as a filling for other desserts, such as malasadas from Leonards or the amazing vanilla haupia pie at the Snack Shack on &lt;a href="http://okasaki.blogspot.com/2010/07/eating-my-way-across-kauai.html"&gt;Kauai&lt;/a&gt;.  If you're willing to use canned coconut milk, it's very easy to make at home.  Whisk 3 cups canned coconut milk with 5 tablespoons sugar and 5 tablespoons cornstarch.  Keep whisking over heat until bubbly.  Spread into a pan, and refrigerate until firm.  Cut into squares to serve.  (Some people substitute water or milk for up to half of the coconut milk.)&lt;/p&gt;
&lt;h3&gt;Manapua&lt;/h3&gt;
&lt;p&gt;The name &amp;ldquo;manapua&amp;rdquo; literally translates to &amp;ldquo;flower power&amp;rdquo;, which makes no sense because it was a corruption of the longer phrase &amp;ldquo;mea ono pua'a&amp;rdquo; (roughly, pork pastry).&lt;/p&gt;
&lt;p&gt;Manapua is the Hawaiian version of a Chinese bao, with the bun made out of a dough similar to Portuguese sweet bread.  The buns can be baked or steamed, and the fillings can be savory or sweet, with char siu (Chinese roast pork) being the most popular.  Manapua are so popular on Hawaii that they used to be sold door-to-door by the &amp;ldquo;manapua man&amp;rdquo; (Hawaii's version of the Good Humor Man).  These days the manapua man sells out of a truck.&lt;/p&gt;

&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/ACBP9wpl99euV81GtATOmA?select=5MG6E0VDmFVbShZe8BRt7Q"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEHXfGx7KGI/AAAAAAAAAD4/Urw5ro5ANls/s320/l-2.jpeg" border="0" alt="Char Siu Manapua (photo by Chelsey C.)" id="BLOGGER_PHOTO_ID_5494909949764642914" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/royal-kitchen-honolulu"&gt;Royal Kitchen&lt;/a&gt;&lt;/b&gt; (on the pedestrian part of River Street just off N Kukui Street): If I could transport one shop from Hawaii to my neighborhood, this would be it.  I could eat a couple of these EVERY SINGLE DAY for breakfast.  I loved the cha siu manapua, and the lup chong manapua was almost as good.  I probably wouldn't bother with the curry chicken manapua again, but I'd still like to try the kalua pork and the Portuguese sausage.  The sweet lovers in my family also enjoyed the coconut manapua and the black sugar manapua.  (Another &lt;i&gt;Lost&lt;/i&gt; sighting: the pedestrian bridge by Royal Kitchen is where they filmed Sun paying off Jin's mother.)&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/0tYdrYX_lElBLSuBOniOgA?select=gcio7EHk7DW8tf4QtsN4QA"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 282px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEHgKGapfyI/AAAAAAAAAEA/ecaQ4KxFjCA/s320/l.jpeg" border="0" alt="Manapua and pork hash (photo by Malia H.)"id="BLOGGER_PHOTO_ID_5494919484494413602" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/libby-manapua-shop-honolulu"&gt;Libby Manapua&lt;/a&gt;&lt;/b&gt; (corner of Kalihi and Kalani): After enjoying Royal Kitchen so much, we stopped here on our way to the airport to pick up lunch.  My internet research had turned up Libby Manapua as a strong contender for best manapua on the island.  My verdict was that Royal Kitchen is better.  The buns at Libby were bigger than Royal Kitchen's, but with too little filling for all that bread.  Also, Libby offered a much smaller selection of fillings.  On the other hand, the &lt;i&gt;pork hash&lt;/i&gt; at Libby was fantastic.  You can see these little pork-filled dumplings in the upper right corner of the box.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/sing-cheong-yuan-bakery-honolulu-2"&gt;Sing Cheong Yuan Bakery&lt;/a&gt;&lt;/b&gt; (Maunakea Street): Not really manapua, but close enough that I'll mention it here.  We never went into the store, but we were able to sample their &lt;i&gt;ma tai su&lt;/i&gt;, a flaky bun filled with an intensely flavorful pork/shrimp mixture.  Heavenly!&lt;/p&gt;
&lt;h3&gt;Noodles&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/ramen-nakamura-honolulu"&gt;Ramen Nakamura&lt;/a&gt;&lt;/b&gt; (on Kalakaua Avenue in Waikiki): After binging on Hamura Saimin on &lt;a href="http://okasaki.blogspot.com/2010/07/eating-my-way-across-kauai.html"&gt;Kauai&lt;/a&gt;, I wanted to compare it to the &amp;ldquo;real thing&amp;rdquo;.  Ramen Nakamura was very, very good&amp;#8210;I'd happily eat there again anytime&amp;#8210;but a notch below Hamura.  To me, the biggest difference was in the noodles themselves, but I also had a slight preference for Hamura's broth.  To be fair, Ramen Nakamura offers several different broths; I had the miso, but maybe the shio or shoyu broth would have fared better.  Someone whose opinion I trust later told me that Ramen Nakamura has the best ramen in the city, and I believe it.  Any negativity here should be read as praise for Hamura rather than a knock against Ramen Nakamura.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/ying-leong-look-funn-factory-honolulu"&gt;Ying Leong Look Funn Factory&lt;/a&gt;&lt;/b&gt; (Keekaulike Street): We were lucky enough to tour this tiny factory, where they still make &lt;i&gt;look funn&lt;/i&gt; rice noodles by hand.  First, they ladle the soupy noodle batter onto aluminum sheet pans, then steam them in the silver steamers shown in back.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEH4Bfr4q0I/AAAAAAAAAEQ/k7aSrVNDg0o/s1600/noodle1.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 400px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEH4Bfr4q0I/AAAAAAAAAEQ/k7aSrVNDg0o/s400/noodle1.jpg" border="0" alt="(photo by Maria Ebling)"id="BLOGGER_PHOTO_ID_5494945724937841474" /&gt;&lt;/a&gt;
When the pans come out of the steamer, they are stacked in front of fans to cool.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEH5obuUphI/AAAAAAAAAEY/VrBATo0LEh4/s1600/noodle3.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEH5obuUphI/AAAAAAAAAEY/VrBATo0LEh4/s400/noodle3.jpg" border="0" alt="(photo by Maria Ebling)"id="BLOGGER_PHOTO_ID_5494947493400847890" /&gt;&lt;/a&gt;
The noodles are carefully peeled out of the pan...
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEH6J9UAevI/AAAAAAAAAEg/xnB7HReWwsw/s1600/noodle2.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEH6J9UAevI/AAAAAAAAAEg/xnB7HReWwsw/s400/noodle2.jpg" border="0" alt="(photo by Maria Ebling)"id="BLOGGER_PHOTO_ID_5494948069352962802" /&gt;&lt;/a&gt;
...and folded into stacks that look like giant calamari.
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_HOXl0OgNHo0/TEH6r2jlvwI/AAAAAAAAAEo/Zcs0WNqT5MY/s1600/noodle5.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 300px;" src="http://4.bp.blogspot.com/_HOXl0OgNHo0/TEH6r2jlvwI/AAAAAAAAAEo/Zcs0WNqT5MY/s400/noodle5.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5494948651654823682" /&gt;&lt;/a&gt;
Most of the noodles shown in these pictures are plain, but you can see small chunks in the batter in the first picture.  These chunks are green onion and either char siu or shrimp.  Below, you can see the finished product, sliced and drizzled with a little bit of soy sauce.  Delicious!
&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/N5FZYX3Xe_Db203POfVL1Q?select=2tfdfG5yX-Usgq8bTt07lQ"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 240px; height: 320px;" src="http://2.bp.blogspot.com/_HOXl0OgNHo0/TEHtoJs6buI/AAAAAAAAAEI/kFJreYhwFi0/s320/l-1.jpeg" border="0" alt="Look Funn (photo by Joshua C.)" id="BLOGGER_PHOTO_ID_5494934294423564002" /&gt;&lt;/a&gt;
&lt;h3&gt;Polynesian Cultural Center Luau&lt;/h3&gt;
&lt;p&gt;We spent a full day at the &lt;a href="http://www.polynesia.com/"&gt;Polynesian Cultural Center&lt;/a&gt;.  It's fun and worth the trip, although if we do it again we would skip the tour guide.  But forget all the cultural stuff&amp;#8210;I'm here to talk about the food!&lt;/p&gt;
&lt;p&gt;First, I have to get something off my chest:  &lt;b&gt;Dear PCC, The shave ice you sell in the park really should be shaved, not crushed!&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Ok, I feel much better now.&lt;/p&gt;
&lt;p&gt;The shave ice may have been disappointing, but their luau more than made up for it.  Everything I tried was at least good, with many dishes reaching into outstanding territory, including
&lt;ul&gt;
&lt;li&gt; fabulous &lt;i&gt;kalua pig&lt;/i&gt;, probably the second best I had on the trip
&lt;li&gt; outstanding &lt;i&gt;taro rolls&lt;/i&gt; (purple dinner rolls made with taro flour)
&lt;li&gt; the best &lt;i&gt;poke&lt;/i&gt; I had on the trip (poke is marinated chunks of raw ahi, although I found out later that PCC uses a Tahitian recipe rather than Hawaiian)
&lt;li&gt; a wonderful sweet potato salad made from purple Okinawan sweet potatoes
&lt;li&gt; fabulous &lt;i&gt;pipikaula&lt;/i&gt; (similar to beef jerky, but softer)
&lt;li&gt; the best &lt;i&gt;haupia&lt;/i&gt; I had on the trip
&lt;/ul&gt;
&lt;p&gt;Of course, they also had luau staples such as poi, lomilomi salmon, chicken long rice, chicken teriyaki, and fresh pineapple.  All these were good, but not as memorable as the above dishes.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.flickr.com/photos/18268873@N00/507309003"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEKr8nTOdQI/AAAAAAAAAEw/mDanDSiEaRw/s320/507309003_89218b7bbf.jpg" border="0" alt="Pineapple with li hing powder (photo by millietastic)" id="BLOGGER_PHOTO_ID_5495143553175549186" /&gt;&lt;/a&gt;Speaking of fresh pineapple...  At the family luau we went to for my cousin's first birthday, I gorged myself on fresh pineapple sprinkled with &lt;i&gt;li hing powder&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;A few years ago, I tried &lt;i&gt;li hing mui&lt;/i&gt;, the king of the Hawaiian snack genre known as &amp;ldquo;crack seed&amp;rdquo;.  Li hing mui is a salty dried plum covered with a bright red powder.  The combination is salty, sweet, sour, stains your fingers red, and does funny things to your mouth.  I have to admit I didn't like it.  I think I even used the word &amp;ldquo;disgusting&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;But what I've now learned is that you can get the powder without the plum.  I had it several times this trip sprinkled on fresh pineapple, which takes an already excellent treat up to the next level.  I've heard that the powder is also good sprinkled on other kinds of fruit, on popcorn, even on ice cream.  We brought a bag home that I look forward to experimenting with.&lt;/p&gt;
&lt;h3&gt;New for &lt;i&gt;Lost&lt;/i&gt; Fans&lt;/h3&gt;
&lt;p&gt;I found a website (&lt;a href="http://www.lostvirtualtour.com/welcome.php"&gt;Lost Virtual Tour&lt;/a&gt;) that includes some great pictures of the places I mentioned, showing what they look like in the show and in real life.
&lt;ul&gt;
&lt;li&gt; &lt;a href="http://www.lostvirtualtour.com/lost/filming_locations/lilihabakery/index.html"&gt;The diner from Liliha Bakery&lt;/a&gt;
&lt;li&gt; &lt;a href="http://www.lostvirtualtour.com/lost/filming_locations/kila_kalikimaka/index.html"&gt;The bridge by Royal Kitchen&lt;/a&gt;
&lt;/ul&gt;
To my surprise, this site also shows &lt;a href="http://www.lostvirtualtour.com/lost/filming_locations/murphys/index.html"&gt;the pub where we went to our family luau&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-717311987727430003?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/717311987727430003/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=717311987727430003' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/717311987727430003'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/717311987727430003'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2010/07/eating-my-way-across-oahu.html' title='Eating My Way Across Oahu'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_HOXl0OgNHo0/TEDImkPaFRI/AAAAAAAAADA/7TD1v1-O0jU/s72-c/mochi-with-red-bean.jpg' height='72' width='72'/><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-6938181801861242194</id><published>2010-07-16T12:14:00.002-04:00</published><updated>2010-07-18T03:50:06.558-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='food'/><title type='text'>Eating My Way Across Kauai</title><content type='html'>&lt;p&gt;See also &lt;a href="http://okasaki.blogspot.com/2010/07/eating-my-way-across-oahu.html"&gt;Eating My Way Across Oahu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;I love to eat, so I'm going to temporarily hijack this blog with some dining recommendations from our recent vacation in Hawaii.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;We just got back from almost two weeks in Hawaii.  My favorite part of the trip was eating my way across Kauai and Oahu.  In planning for the trip, I got a lot of good tips from food blogs and other internet reviews, so I'm going to pay it forward by reporting on our dining hits and misses.  This post will cover Kauai, and the next post will cover Oahu.&lt;/p&gt;
&lt;p&gt;Be aware that many of these places take cash only.&lt;/p&gt;
&lt;h3&gt;Must Try&lt;/h3&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/JH2tvTBx0PAZ4XTlFmUrlQ?select=w5J35ePhxmh2E4cEV8BNvw"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/TEBP2PHafHI/AAAAAAAAACI/aW8NIIYDq-Y/s320/l.jpeg" border="0" alt="Saimin Special (Photo by Christina C.)" id="BLOGGER_PHOTO_ID_5494479338581163122" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/hamura-saimin-stand-lihue-2"&gt;Hamura Saimin Stand&lt;/a&gt;&lt;/b&gt; (Lihue, close to the airport): This place is a dive...and I mean that in the best possible way. It's old, run-down, hard-to-find, and tiny, so you'll probably have to wait for a few minutes. But the food is amazing, not to mention cheap and plentiful!  I'm a huge fan of ramen (the real stuff, not the dried packages you find in the grocery store) and Hamura serves some of the best you'll find this side of Japan.  The “special” (shown to the right) is a huge bowl filled with wonderful noodles and broth, and then topped with char siu (roast pork), won tons, fish cake, ham, green onions, cabbage, and a hard-boiled egg.  The bbq sticks (beef or chicken), crispy wontons, and lilikoi (passion fruit) chiffon pie are also excellent, but be aware that they run out of the pie.  Seating is at a single zig-zag counter, so be prepared to chat with your neightbors.&lt;/p&gt;
&lt;h3&gt;Highly Recommended&lt;/h3&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/5Fq5MhhxEj51wsOwUxhZZw?select=moq522LB5MpQjfMxFEW6TQ"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_HOXl0OgNHo0/TEBlVnu9RlI/AAAAAAAAACY/7H0ZUDqnd7k/s320/l.jpeg" border="0" alt="Hanalei Dolphin (photo by Cheri A G.)" id="BLOGGER_PHOTO_ID_5494502967509599826" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/hanalei-dolphin-restaurant-hanalei"&gt;Hanalei Dolphin Restaurant&lt;/a&gt;&lt;/b&gt; (Hanalei, on the right as you first drive into town): The best “fancy” meal we had on the trip.  I had the shutome (broadbill swordfish) and my wife had the walu (Hawaiian butter fish).  The shutome was among the best fish I've had in my life, and the walu was almost as good.  Both were simply grilled, and then served with a slice of lemon and some drawn butter.  The butter, in particular, was a revelation for me.  Sure, you often see it with lobster and the like, but usually not with fish.  After experiencing how much it enhanced the fish here, I'll have to ask for it at other places.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/RLizju7GoEXDMO248MESSg?select=g441bR_5qP1WvcCy68y7iQ"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEBkFpT-0ZI/AAAAAAAAACQ/5owpw0TcB8U/s320/l-1.jpeg" border="0" alt="Puka Dog (photo by Diana H.)" id="BLOGGER_PHOTO_ID_5494501593543790994" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/puka-dog-koloa"&gt;Puka Dog&lt;/a&gt;&lt;/b&gt; (Poipu, inside the Poipu Shopping Village): My son LOVED these, declaring them almost as good as my father's sweet-and-sour chicken wings, which is his high-water mark for non-dessert foods.  They take a huge unsliced bun, and stick it onto a big spike, which both makes a hole for the dog and toasts the inside of the bun.  They then put some toppings in the hole, fill the bun with a polish sausage, and add some more toppings to the tip of the sausage sticking out of the hole.  Okay, the hole thing is a gimmick, but where they really shine is the toppings‒six different fruit relishes including mango, pineapple, papaya, banana, star fruit, and coconut (mango and pineapple are probably the best).  They also include a mayonnaise-like “garlic lemon secret sauce”.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/72kRIAYe_GlTOkFk-RJ2nQ?select=EcMSJP-IT3sAZKGhPaKbnQ"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEBm44UFjSI/AAAAAAAAACg/G8ZdKDRk864/s320/l-1.jpeg" border="0" alt="Pat's Taqueria (photo by Mark W.)" id="BLOGGER_PHOTO_ID_5494504672767348002" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/pats-taqueria-hanalei"&gt;Pat's Taqueria (aka Pat's Taco Wagon)&lt;/a&gt;&lt;/b&gt; (Hanalei, by the base of the pier): On the mainland, lunch wagons are usually nothing special, but Hawaii has a tradition of great food served out of trucks.  Pat's Taco Wagon is an excellent example.  My first visit, I had the kalua pork burrito, which was very good.  My second visit, I had the carne asada taco, which was mind-blowing.  Both were kind of drippy, so be sure to lean over when you eat them.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/VcFDqt0Cm0IlPeSpl324Ig?select=6OxSY02KecPl_0Knda-Xfg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://4.bp.blogspot.com/_HOXl0OgNHo0/TEBqTzROiGI/AAAAAAAAACo/ay3nn1kAzc4/s320/l.jpeg" border="0" alt="Vanilla haupia pie (photo by alli t.)" id="BLOGGER_PHOTO_ID_5494508433804527714" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/village-snack-and-bakery-shop-hanalei"&gt;Village Snack &amp;amp; Bakery (aka The Snack Shack)&lt;/a&gt;&lt;/b&gt; (Hanalei, in the back of the Ching Young Village Shopping Center): My favorite dessert on the island, vanilla haupia pie. Mmmm! If you get there early in the morning, you may also be lucky enough to get their fried mochi (three balls of mochi with a sugary coating on a stick).  Their loco moco (a Hawaiian tradition with two scoops of rice, a hamburger steak, and two fried eggs, covered with brown gravy) and teriyaki beef sandwich were also outstanding, but the pancakes and apple cobbler were only so-so.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/qrHJwpDrwrp_FX0Uq0BHng?select=P2z57x-PoysDDAAwKxEPJA"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://2.bp.blogspot.com/_HOXl0OgNHo0/TEBtxiK1odI/AAAAAAAAACw/ElgA8uge5is/s320/l.jpeg" border="0" alt="Shave Ice Paradise (photo by beno h.)" id="BLOGGER_PHOTO_ID_5494512243145286098" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/shave-ice-paradise-hanalei-2"&gt;Shave Ice Paradise&lt;/a&gt;&lt;/b&gt; (Hanalei, across the street from the Ching Young Village Shopping Center): Shave ice is everywhere in Hawaii.  Think giant snow cone, but made with shaved ice instead of crushed ice.  The difference in texture is substantial, smooth instead of pebbly.  You have a choice of many different syrups, and can add on ice cream underneath or sweetened condensed milk on top.  The ice cream at the bottom didn't do much for me because you end up eating the top half of the ice without it, but the sweetened condensed milk on top (sometimes called a sno cap) is fantastic, changing what can sometimes be sickly sweet to sweet and creamy.  Shave ice stands are very common, and there's not necessarily a lot of difference between them, but this one was the best we tried.&lt;/p&gt;
&lt;p&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.yelp.com/biz_photos/8qTkY3ZqSx115u8uph14zQ?select=QMhG1bsnfklnJU54mm8AQg"&gt;&lt;img style="float:right; margin:0 0 10px 10px;cursor:pointer; cursor:hand;width: 320px; height: 240px;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/TEBvapnmeqI/AAAAAAAAAC4/Movf7fJyg7k/s320/l-1.jpeg" border="0" alt="Hanalei Taro &amp;amp; Juice Company (photo by Janet D.)" id="BLOGGER_PHOTO_ID_5494514049031240354" /&gt;&lt;/a&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/hanalei-taro-and-juice-co-hanalei"&gt;Hanalei Taro &amp;amp; Juice Company&lt;/a&gt;&lt;/b&gt; (Hanalei, in front of Kayak Kauai): Another lunch wagon.  Plate lunches are a Hawaiian tradition with two scoops of rice, macaroni salad, and some kind of meat.  I had the kalua pork plate lunch, which turned out to be the best kalua pork I tried on the island.  The plate lunch also came with a little slice of their mochi cake, which is very good.  They are famous for their smoothies, with use a taro base in addition to various combinations of fruit.  My smoothie was good, but nothing special.  The downside is that it's hard to find them open!  I think they move around, but I didn't know where to look other than their main location.&lt;/p&gt;
&lt;h3&gt;Recommended&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/kountry-kitchen-kapaa-2"&gt;Kountry Kitchen&lt;/a&gt;&lt;/b&gt; (Kapaa): Gigantic macadamia nut pancakes, which were fantastic with coconut syrup.  I had the special loco moco, which had kalua pork instead of the usual hamburger steak, and it was very good also.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/bubba-burgers-hanalei"&gt;Bubba Burgers&lt;/a&gt;&lt;/b&gt; (Hanalei, across the street from the Ching Young Village Shopping Center): Try the teriyaki burger with pineapple.  These are fast food burgers rather than restaurant burgers, but still good.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/lapperts-hawaii-hanalei"&gt;Lappert's Hawaii&lt;/a&gt;&lt;/b&gt; (Princeville, in the Princeville Center): Good ice cream with unusual flavors.  I'd say good, but not great.  Both &lt;a href="http://www.yelp.com/biz/kilauea-video-ice-cream-and-candy-kilauea"&gt;Kilauea Video and Ice Cream&lt;/a&gt; (in Kilauea) and &lt;a href="http://www.yelp.com/biz/pinks-creamery-hanalei"&gt;Pink's Creamery&lt;/a&gt; (in Hanalei) sounded better to me, but we didn't get to try those.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/banana-joes-kilauea"&gt;Banana Joe's&lt;/a&gt;&lt;/b&gt; (Kilauea, just off the highway): I didn't go, but my family loved their frostees.  They also had some great fresh fruit, including lychees and “apple bananas”.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/tip-top-motel-cafe-and-bakery-lihue"&gt;Tip Top Motel Cafe &amp;amp; Bakery&lt;/a&gt;&lt;/b&gt; (Lihue): Very busy, but incredibly fast service.  The pancakes were good, but not  as good as Kountry Kitchen's.  I enjoyed the bento breakfast, which included teriyaki beef, chicken wings, Goteborg sausage, rice and macaroni salad.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/the-mediterranean-gourmet-hanalei"&gt;Mediterranean Gourmet&lt;/a&gt;&lt;/b&gt; (Hanalei, way past the main drag, almost to Haena, at the Hanalei Colony Resort): We ate two lunches there, with good gyros, falafels, and chicken kebabs.  We also went to their once-a-week luau since we were staying at the resort.  The food at the luau was only so-so, but the entertainment was fun, if much lower key than many of the fancier tourist luaus.&lt;/p&gt;
&lt;h3&gt;Not Recommended&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/bar-acuda-hanalei-2"&gt;Bar Acuda&lt;/a&gt;&lt;/b&gt; (Hanalei): We were disappointed in this highly recommended tapas bar.  The food we had there was good, some of it excellent.  The problem is that their menu is just too limited, with only about a dozen choices for tapas.  After running through everything we wanted to try out of their tapas offerings, we proceeded down the street to Bubba Burgers because the kids were still hungry.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/the-hanalei-gourmet-hanalei"&gt;Hanalei Gourmet&lt;/a&gt;&lt;/b&gt; (Hanalei): Okay, but nothing special.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href="http://www.yelp.com/biz/bouchons-hanalei-hanalei"&gt;Bouchons Hanalei&lt;/a&gt;&lt;/b&gt; (Hanalei):  Nice atmosphere, but mediocre food.  I did not try their sushi, so maybe that's better.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-6938181801861242194?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/6938181801861242194/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=6938181801861242194' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/6938181801861242194'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/6938181801861242194'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2010/07/eating-my-way-across-kauai.html' title='Eating My Way Across Kauai'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_HOXl0OgNHo0/TEBP2PHafHI/AAAAAAAAACI/aW8NIIYDq-Y/s72-c/l.jpeg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7503515112491923119</id><published>2009-11-23T23:35:00.001-05:00</published><updated>2009-11-23T23:37:04.829-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='tournament'/><title type='text'>Round-Robin Tournament Scheduling</title><content type='html'>&lt;p&gt;For the last several years, I've held an in-class tournament on the last class day before Thanksgiving.  Everybody's mind is elsewhere anyway, so the positive vibes generated by an hour spent hootin' and hollerin' are far more valuable than class content that would be forgotten long before the turkey made it into the oven.&lt;/p&gt;

&lt;p&gt;Tomorrow's the big day, so I've spent part of today working out the tournament schedule.  As usually seems to be the case, I have a different number of teams this year from past years, so I had to make a new schedule from scratch.  I keep forgetting how I did it last time, but I always seem to converge back on the same technique.  I finally decided to write down the technique so I can just look it up next year.  Also, I'm hoping somebody can tell me what this technique is called, since it can't possibly be original.&lt;/p&gt;


&lt;p&gt;Unless I have too many teams, I like to run a round-robin tournament, where everybody plays everybody else.  There's a well-known algorithm for scheduling such a tournament by hand.  I'll illustrate this algorithm with 6 teams, numbered 0&amp;#8211;5.  Start by writing the teams down in two rows, as follows:
&lt;pre&gt;
   0 1 2
   5 4 3
&lt;/pre&gt;
The columns say which teams play each other.  In this case, team 0 plays team 5, team 1 plays team 4, and team 2 plays team 3.  

&lt;p&gt;
Now, leave team 0 in place, but rotate teams 1&amp;#8211;5 one position clockwise.
&lt;pre&gt;
   0 5 1
   4 3 2
&lt;/pre&gt;
In this round, team 0 plays team 4, team 5 plays team 3, and team 1 plays team 2.  This process continues for three more rounds:
&lt;pre&gt;
   0 4 5
   3 2 1

   0 3 4
   2 1 5

   0 2 3
   1 5 4
&lt;/pre&gt;
For an even number of teams, this technique generates a schedule with N&amp;minus;1 rounds, and N/2 games per round.  For an odd number of teams, you add an extra dummy team, yielding a schedule with N rounds and (N&amp;minus;1)/2 games per round.  In each round, the team scheduled against the dummy gets a bye.

&lt;p&gt;Many games have a slight asymmetry, such as a homefield advantage or a first-move advantage.  For my game, the &amp;ldquo;red&amp;rdquo; team has a very small advantage over the &amp;ldquo;blue&amp;rdquo; team.  In tournaments for such games, it is important to balance the number of &amp;ldquo;home&amp;rdquo; games and &amp;ldquo;away&amp;rdquo; games played by each team.  In the above algorithm, this is accomplished by making the top row the home team in odd-numbered rounds and the bottom row the home team in even-numbered rounds.  (Note that, when N is even, half the teams will get one extra home game.)

&lt;p&gt;Okay, so the above technique is easy, but it has a major drawback for my purposes, at least when N is odd.  Because the tournament must be completed by the end of the class period, I need to be ready to drop games from the schedule if it looks like we're running long.  The easiest way to accomplish this is to drop an entire round.  But when N is odd, one team has a bye, which means that that team will end up playing a different number of games from everybody else, which in turn can make it difficult to determine the winner of the tournament.&lt;/p&gt;

&lt;p&gt;
To avoid this problem, I use the following technique.  I organize the schedule in N/2 rounds, rounded down if N is odd.  In each round (except possibly the last), every team plays twice: one home game and one away game.  The rule is that, in round R, team X plays at home against team (X+R) mod N, and away against team (X&amp;minus;R) mod N.  (If you don't remember how mod works, it simply means that the team numbers wrap around.)  For example, here is a schedule for 7 teams, numbered 0&amp;#8211;6.
&lt;pre&gt;
   Round 1: 0-1 1-2 2-3 3-4 4-5 5-6 6-0

   Round 2: 0-2 1-3 2-4 3-5 4-6 5-0 6-1

   Round 3: 0-3 1-4 2-5 3-6 4-0 5-1 6-2
&lt;/pre&gt;
Each game is listed as HOME TEAM&amp;#8211;AWAY TEAM.

&lt;p&gt;
If N is even, then the last round is treated specially.  As described so far, the last round in an 8-team tournament would look like
&lt;pre&gt;
   Round 4: 0-4 1-5 2-6 3-7 4-0 5-1 6-2 7-3
&lt;/pre&gt;
This involves repeat games, such as 0-4 and 4-0.  To prevent such repeats, we chop off the second half of the last round when N is even.

&lt;p&gt;
Again, the advantage of this scheduling algorithm is that I can delete a round on the fly without causing an imbalance in the number of games that each team plays.  Deleting a round also maintains the balance between home games and away games for each team, although that's a lesser concern.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7503515112491923119?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7503515112491923119/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7503515112491923119' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7503515112491923119'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7503515112491923119'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2009/11/round-robin-tournament-scheduling.html' title='Round-Robin Tournament Scheduling'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7961033583491130229</id><published>2009-10-22T20:17:00.010-04:00</published><updated>2009-10-23T15:24:45.629-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Haskell'/><category scheme='http://www.blogger.com/atom/ns#' term='crazy types'/><title type='text'>Binomial queues as a nested type</title><content type='html'>&lt;p&gt;&lt;i&gt;&lt;b&gt;Warning: this is probably only of interest to functional programmers.&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Maciej Kotowicz recently asked on the Haskell Cafe mailing list about implementing binomial queues (also known as &lt;a href="http://en.wikipedia.org/wiki/Binomial_heap"&gt;binomial heaps&lt;/a&gt;) using fancy type machinery so that the type-checker can enforce the shape invariants of the data structure.  This reminded me of a discussion I had with some colleagues in the summer of 1998 about using nested types to enforce these kinds of invariants.  A little digging around in mail archives yielded this email, presented here with some light formatting and a few fixed typos.&lt;/i&gt;&lt;/p&gt;



&lt;p&gt;I've been playing with binomial queues as a nested type, and I think
you'll find the end result interesting.&lt;/p&gt;

&lt;h3&gt;REVIEW&lt;/h3&gt;

&lt;p&gt;Let me first quickly review the usual implementation of binomial queues.
Recall that a binomial tree has the shape

&lt;pre&gt;
data Tree a = Node a [Tree a]
&lt;/pre&gt;
A binomial tree of rank k has k children, of ranks k-1 .. 0 (stored in the
list in decreasing order of rank).  Note that we can combine two
heap-ordered binomial trees of rank k to get a heap-ordered binomial
tree of rank (k+1) as follows:

&lt;pre&gt;
combine a@(Node x xs) b@(Node y ys)
   | x &lt;= y    = Node x (b : xs)
   | otherwise = Node y (a : ys)
&lt;/pre&gt;
Now a binomial queue is a list of heap-ordered binomial trees of increasing 
height (but not necessarily of consecutive ranks).  We'll represent the ranks
of those trees that are present by their position in the tree.  Thus,
some ranks will be empty.  This could be implemented as
&lt;pre&gt;
type Binom a = [Maybe (Tree a)]
&lt;/pre&gt;
or somewhat more efficiently as
&lt;pre&gt;
data Binom a = Nil
             | Zero (Binom a)
             | One (Tree a) (Binom a)
&lt;/pre&gt;
or better still by unboxing the Tree in the One constructor
&lt;pre&gt;
data Binom a = Nil
             | Zero (Binom a)
             | One a [Tree a] (Binom a)
&lt;/pre&gt;
I won't go over all the operations -- they are amply covered elsewhere.
I'll just describe two functions.  The first, add, takes a tree and a
list (where the tree has the same rank as the first position in the
list), and returns a new list.  It works basically like the increment
function on binary numbers.
&lt;pre&gt;
add :: Ord a =&gt; a -&gt; [Tree a] -&gt; Binom a -&gt; Binom a
add x xs Nil = One x xs Nil
add x xs (Zero h) = One x xs h
add x xs (One y ys h)
  | x &lt;= y    = Zero (add x (Node y ys : xs) h)
  | otherwise = Zero (add y (Node x xs : ys) h)
&lt;/pre&gt;
The merge function is similar and works basically like the addition
function on binary numbers.

&lt;p&gt;
Finally, the getMin function returns the minimum element of a queue
paired with the queue without that element.  The helper function
getMin_ returns a triple of the minimum element in some suffix of the
queue, the list of children associated with that minimum element, and
the suffix without that element.
&lt;pre&gt;
getMin_ :: Ord a =&gt; Binom a -&gt; (a, [Tree a], Binom a)
getMin_ (Zero h) = case getMin_ h of
                     (y,ys,h') -&gt; (y,ys,Zero h')
getMin_ (One x xs Nil) = (x,xs,Nil)
getMin_ (One x xs h) = case getMin_ h of
                         (y,ys,h') | x &lt;= y    -&gt; (x,xs,Zero h)
                                   | otherwise -&gt; (y,ys,One x xs h')

getMin :: Ord a =&gt; Binom a -&gt; (a, Binom a)
getMin h = let (x,xs,h') = getMin_ h
           in (x,merge (list2binom xs Nil) h')

list2binom [] h = h
list2binom (Node x xs : ys) h = list2binom ys (One x xs h)
&lt;/pre&gt;
Note that when getMin receives a list of children, it converts them
to a valid binomial queue by reversing the list (and changing each
pair of a Node constructor and a (:) constructor to a One constructor).

&lt;h3&gt;NESTED REPRESENTATION -- FIRST ATTEMPT&lt;/h3&gt;

&lt;p&gt;
By following the same approach we have been using to design nested
datatypes, we get the following representation of binomial queues.

&lt;pre&gt;
data Binom_ a b = Nil
                | Zero (Binom_ a (Trees a b))
                | One a b (Binom_ a (Trees a b))

type Trees a b = (a, b, b)

type Binom a = Binom_ a ()
&lt;/pre&gt;
Here the list of children
&lt;pre&gt;
  (Node x3 xs3 : Node x2 xs2 : Node x1 xs1 : Node x0 xs0 : [])
&lt;/pre&gt;
is being represented by the nested triples
&lt;pre&gt;
  (xs3,xs3', (x2,xs2', (x1,xs1', (x0,xs0', ()))))
&lt;/pre&gt;
(where xsN' is the appropriate conversion of xsN).

&lt;p&gt;All the functions are perfectly straightforward, except for getMin and
getMin_ which must incrementally build up the reversing function to
convert
&lt;pre&gt;
  (xs3,xs3', (x2,xs2', (x1,xs1', (x0,xs0', ()))))
&lt;/pre&gt;
to
&lt;pre&gt;
  One x0 xs0' (One x1 xs1' (One x2 xs2' (One x3 xs3' Nil)))
&lt;/pre&gt;
As a result of building up this reverse function incrementally, this
implementation ends up being roughly 10% slower than the original.

&lt;h3&gt;INTERLUDE ON REVERSING LISTS&lt;/h3&gt;

Suppose we want to support the following ADT.  We want sequences with
three operations:

&lt;pre&gt;
empty :: ReversableSeq a
cons  :: a -&gt; ReversableSeq a -&gt; ReversableSeq a
rev   :: ReversableSeq a -&gt; [a]
&lt;/pre&gt;
with the obvious semantics.  cons must take O(1) time, but rev may take
O(n) time.  A list is a reasonable implementation with
&lt;pre&gt;
type ReversableSeq a = [a]
empty = []
cons = (:)
rev = reverse
&lt;/pre&gt;
but, if you think about it, there's a fair amount of interpretive
overhead in the pattern matching that reverse performs at every step.
Way back in 1985, John Hughes came up with a representation that
avoids this overhead:
&lt;pre&gt;
type ReversableSeq a = [a] -&gt; [a]
empty = id
cons x xs = xs . (x:)
rev xs = xs []
&lt;/pre&gt;
The result of cons 1 (cons 2 (cons 3 empty)) is
&lt;pre&gt;
id . (3:) . (2:) . (1:)
&lt;/pre&gt;
which, when applied to [] by the rev function, yields [3,2,1].  One way to 
think of this representation is as lists with "holes" at the ends.  The
cons operation fills in this hole with an element and another hole, and the 
rev operation fills in the hole with [].  (This is quite similar to
difference lists in logic programming...)

&lt;p&gt;Applying this trick to the regular representation of binomial queues
yields
&lt;pre&gt;
data Binom a = Nil
             | Zero (Binom a)
             | One a (Binom a -&gt; Binom a) (Binom a)
&lt;/pre&gt;
which turns out to be about 10% faster than the original representation.

&lt;h3&gt;NESTED REPRESENTATION -- SECOND ATTEMPT&lt;/h3&gt;

&lt;p&gt;Ok, let's try to make a nested datatype out of this.  Conceptually, the 
nesting should keep track of our position in the queue so that we know
what rank the current tree has and can't possibly mix up trees of different
ranks.  We hypothesize some Base type for the beginning of the list,
and some type transformer Succ that modifies the type as we 
move down the queue.
&lt;pre&gt;
type Base = ???
type Succ b = ???  -- this might need to be Succ a b

type Binom a = Binom_ a Base

data Binom_ a b = Nil
                | Zero (Binom_ a (Succ b))
                | One a (Binom_ a ??? -&gt; Binom_ a ???) (Binom_ a (Succ b))
&lt;/pre&gt;
Now, what should the missing types in the One constructor be?  Well,
the function (Binom_ a ??? -&gt; Binom_ a ???) represents the children
of the current node.  If this node is of rank k, then these children
are of ranks 0 .. k-1.  The function (Binom_ a ??? -&gt; Binom_ a ???)
takes a queue starting at rank k and adds the children to the front of
it, yielding a queue starting at rank 0.  So the ???'s can be filled in as
&lt;pre&gt;
                | One a (Binom_ a b -&gt; Binom_ a Base) (Binom_ a (Succ b))
&lt;/pre&gt;
or just
&lt;pre&gt;
                | One a (Binom_ a b -&gt; Binom a) (Binom_ a (Succ b))
&lt;/pre&gt;
Now, what should the types Base and Succ be?  It doesn't matter because
we never construct data of those types, we simply use the types to
discriminate between positions in the queue.  So we can define Base
and Succ as
&lt;pre&gt;
type Base = Void
newtype Succ b = S Void
&lt;/pre&gt;

I think this is a very interesting type for several reasons:
&lt;ul&gt;
&lt;li&gt;It includes an arrow type, which we haven't seen much.
&lt;li&gt;The RHS of the datatype definition (in fact, just the One constructor)
has occurrences of Binom_ at no fewer than three different types
&lt;pre&gt;
Binom_ a b
Binom_ a Base
Binom_ a (Succ b)
&lt;/pre&gt;
    I've seen two before, but not three.
&lt;li&gt;It includes types which are never used, but are merely there to
    capture certain invariants (in this case, that trees of different
    ranks should never be confused).  &lt;i&gt;[2009 Comment: Today, these are called &lt;a href="http://www.haskell.org/haskellwiki/Phantom_type"&gt;phantom types&lt;/a&gt;.]&lt;/i&gt; In some ways this might make
    this type less interesting, but an interesting consequence is that the
    code satisifes a certain "type erasure" property: if you erase the
    types from all the functions, you get code for the optimized
    regular representation.
&lt;/ul&gt;

Because of this "type erasure" property, you might expect it to be just
as fast as the optimized regular representation, but in fact it is roughly
10% slower -- or roughly as fast as the original regular representation.
This is because the extra types hinder a certain optimization that the
programmer might make (and which I did make in the optimized regular 
representation).

&lt;p&gt;
Recall the type of the getMin_ function from the original regular
representation, and the way it was used by getMin.
&lt;pre&gt;
getMin_ :: Ord a =&gt; Binom a -&gt; (a, [Tree a], Binom a)

getMin :: Ord a =&gt; Binom a -&gt; (a, Binom a)
getMin h = let (x,xs,h') = getMin_ h
           in (x,merge (list2binom xs Nil) h')
&lt;/pre&gt;
For the optimized regular representation, this becomes
&lt;pre&gt;
getMin_ :: Ord a =&gt; Binom a -&gt; (a, Binom a -&gt; Binom a, Binom a)

getMin :: Ord a =&gt; Binom a -&gt; (a, Binom a)
getMin h = let (x,xs,h') = getMin_ h
           in (x,merge (xs Nil) h')
&lt;/pre&gt;
Now, consider the optimized nested representation.  We can't just write
&lt;pre&gt;
getMin_ :: Ord a =&gt; Binom_ a b -&gt; (a, Binom_ a b -&gt; Binom a, Binom_ a b)
&lt;/pre&gt;
because we don't know the rank of the tree that the second component of
the triple came from.  (Note that if we had existential types, we could 
write
&lt;pre&gt;
getMin_ :: Ord a =&gt; Binom_ a b -&gt; 
                    (a, exists c. Binom_ a c -&gt; Binom a, Binom_ a b)

getMin :: Ord a =&gt; Binom a -&gt; (a, Binom a)
getMin h = let (x,xs,h') = getMin_ h
           in (x,merge (xs Nil) h')
&lt;/pre&gt;
Some implementations do in fact support existential types, but in limited
ways that would carry efficiency costs of their own...)

&lt;p&gt;
Instead of returning the children and then applying them to Nil at the
end, we apply the children to Nil first, and then return the result,
yielding the type
&lt;pre&gt;  
getMin_ :: Ord a =&gt; Binom_ a b -&gt; (a, Binom a, Binom_ a b)

getMin :: Ord a =&gt; Binom a -&gt; (a, Binom a)
getMin h = let (x,xs,h') = getMin_ h
           in (x,merge xs h')
&lt;/pre&gt;
This depends on laziness to evaluate only the children of the final
minimum, and not all the children of the temporary minimums along the
way.  However, this does mean that we build a lot more thunks of the
form (xs Nil) along the way.  And building these thunks is apparently
quite expensive.

&lt;p&gt;&lt;i&gt;&lt;b&gt;2009 Addendum&lt;/b&gt; Ralf Hinze considers a similar representation in Section 6 of &lt;a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.46.571"&gt;Numerical Representations as Higher-Order Nested Datatypes&lt;/a&gt;.  Today, you would probably use fancier type machinery like dependent types or maybe GADTs, but it's still amazing how far you can get with only nested types.&lt;/i&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7961033583491130229?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7961033583491130229/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7961033583491130229' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7961033583491130229'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7961033583491130229'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2009/10/binomial-queues-as-nested-type.html' title='Binomial queues as a nested type'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5609853447723039467</id><published>2008-10-01T23:36:00.000-04:00</published><updated>2008-10-01T23:36:22.874-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='induction'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Score one for induction!</title><content type='html'>&lt;p&gt;One of my favorite textbooks on algorithms&amp;#8212;in spite of the fact that it's twenty years old&amp;#8212;is Udi Manber's &lt;i&gt;Introduction to Algorithms: A Creative Approach&lt;/i&gt;.  However, I have never been tempted to actually use it in class.  You see, the book's greatest strength is also its greatest weakness.&lt;/p&gt;
&lt;p&gt;Most textbooks on algorithms show you a lot of polished algorithms, but provide little or no insight on how to go about designing such algorithms.  Manber's book does a very good job providing such insight, by making an analogy with inductive proofs.  If you have any skill with induction, then you can use Manber's approach to help you design algorithms.  (Of course, this should come as no surprise since writing an inductive proof and writing a recursive function are essentially the same activity.)&lt;/p&gt;
&lt;p&gt;I'm sure you see the flaw here&amp;#8212;most students are even less comfortable with induction than they are with recursion.  It's like trying to help somebody learn to drive a car by making an analogy with riding a unicycle.  For a certain segment of the audience, that analogy might be just what they need, but for the most of the audience, the analogy will only produce puzzled looks.&lt;/p&gt;
&lt;p&gt;I was recently helping a student who was struggling to get a handle on recursion.  He was making the common beginner mistake of trying to think about what happens during the recursive call instead of trusting that the recursive call works (sometimes called the recursive leap of faith).  By sheer coincidence, I had happened to notice the day before that this student had done very well in our discrete math course the previous year.  Time to give it a try...&lt;/p&gt;
&lt;p&gt;&amp;ldquo;You know when you're writing a proof by induction and at some point you use the inductive hypothesis?  That's just like a recursive call.  You don't worry about what happens inside the inductive hypothesis, you just say &amp;lsquo;Assume that it works for N-1...&amp;rsquo;  It's the same with recursion.  You just assume that the recursive call works.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;That comparison actually seemed to help.  Maybe Manber was onto something after all!&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5609853447723039467?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5609853447723039467/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5609853447723039467' title='7 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5609853447723039467'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5609853447723039467'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/10/score-one-for-induction.html' title='Score one for induction!'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>7</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-2816337634377041794</id><published>2008-09-25T23:46:00.002-04:00</published><updated>2008-09-25T23:50:00.702-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Less than vs Greater than</title><content type='html'>&lt;p&gt;From math, we know that X &amp;lt; Y is the same as Y &amp;gt; X.  But in programming, they're not the same.&lt;/p&gt;
&lt;p&gt;Oh, I'm not talking about situations where X and Y have side effects that interact badly.  Instead, I'm talking about situations where one may be more error prone than the other.&lt;/p&gt;
&lt;p&gt;Although the two expressions are mathematically equivalent, they're not &lt;i&gt;linguistically&lt;/i&gt; equivalent.  One focuses attention on something being smaller, and the other focuses attention on something being bigger.  For example, it is a relatively common mistake to go the wrong way when searching a binary search tree.  However, almost every time I run into this error, the student has also written the comparisons backward from the direction I think of as &amp;ldquo;natural&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;Consider the following function for determining whether a given key &lt;tt&gt;x&lt;/tt&gt; appears in a binary search tree &lt;tt&gt;t&lt;/tt&gt;:
&lt;pre&gt;
  function member(x,t) is
     if t = null then return false
     if t.key = x then return true
     if t.key &amp;lt; x then return member(x,t.left)
     if t.key &amp;gt; x then return member(x,t.right)
&lt;/pre&gt;
The fact that I've written this using recursion instead of iteration is irrelevant.  What matters is that the third case goes left when it should go right, and vice versa for the fourth case.  But looking more carefully at that third case
&lt;pre&gt;
     if t.key &amp;lt; x then return member(x,t.left)
&lt;/pre&gt;
I'm not particularly surprised by the error.  The comparison &lt;tt&gt;t.key &amp;lt; x&lt;/tt&gt; focuses attention on something being smaller, and the left side of the tree is where the smaller keys go.  By asking whether &lt;tt&gt;x&lt;/tt&gt; is smaller than &lt;tt&gt;t.key&lt;/tt&gt;, rather than whether &lt;tt&gt;t.key&lt;/tt&gt; is smaller than &lt;tt&gt;x&lt;/tt&gt;, I think we're much less likely to fall into this trap.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-2816337634377041794?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/2816337634377041794/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=2816337634377041794' title='11 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2816337634377041794'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2816337634377041794'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/09/less-than-vs-greater-than.html' title='Less than vs Greater than'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>11</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-2532658920263058700</id><published>2008-09-13T00:10:00.001-04:00</published><updated>2008-09-14T22:49:27.671-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Hey, you got your loop in my recursion!</title><content type='html'>&lt;p&gt;I've written &lt;a href="http://okasaki.blogspot.com/2008/02/boolean-confusion.html"&gt;before&lt;/a&gt; about trying to diagnose students' broken or ineffective mental models from the mistakes they make.  Here's a mistake that I see frequently from students who are not yet comfortable with recursion.&lt;/p&gt;
&lt;p&gt;Say you wanted to write a function to calculate the sum of a list using a loop.  Many students could easily write something like
&lt;pre&gt;
   function sum(list) is
      variable total := 0
      while list /= null do
         total := total + list.item
         list := list.next
      return total
&lt;/pre&gt;
But ask them to write the sum function using recursion, and you might get something like
&lt;pre&gt;
   function sum(list) is
      variable total := 0
      if list = null then
         return total
      else
         total := total + list.item
         return sum(list.next)
&lt;/pre&gt;
Of course, this code always returns 0.  It's pretty clear that the writer had the
iterative algorithm in mind, and doesn't understand that each recursive call to &lt;tt&gt;sum&lt;/tt&gt; creates a new instance of the &lt;tt&gt;total&lt;/tt&gt; variable.&lt;/p&gt;
&lt;p&gt;When I watch such a student writing code like this, he often declares the variable immediately, before even beginning to think about what the recursive decomposition is going to look like, an almost spinal reflex conditioned by several semesters of writing loops.  I can explain recursion until I'm hoarse and draw pictures until my hand cramps up, but I can't compete with the will-o'-the-wisp allure of that variable.  Once it's there, it will almost inevitably lead the student to his doom in the bogs of iterative thinking.&lt;/p&gt;
&lt;p&gt;
One trick to help such a student is to break the cycle where it begins, by getting rid of that variable.  Tell him to write the function &lt;i&gt;without&lt;/i&gt; using any local or global variables.  Or, if he really thinks he needs a variable, to declare it as a constant instead.  Of course, there are times when a variable is perfectly appropriate inside a recursive function, but such examples can often be avoided until the student has a better grasp of recursion.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-2532658920263058700?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/2532658920263058700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=2532658920263058700' title='18 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2532658920263058700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2532658920263058700'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/09/hey-you-got-your-loop-in-my-recursion.html' title='Hey, you got your loop in my recursion!'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>18</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7481880971245369481</id><published>2008-07-31T11:42:00.001-04:00</published><updated>2008-07-31T11:42:22.787-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TradeMaximizer'/><category scheme='http://www.blogger.com/atom/ns#' term='creativity'/><title type='text'>In search of epiphany</title><content type='html'>&lt;p&gt;I watched the movie &lt;a href="http://www.imdb.com/title/tt0377107/"&gt;Proof&lt;/a&gt; last night.  I highly recommend it.  It's not often that mathematicians get so much screen time.&lt;/p&gt;
&lt;p&gt;The nature of mathematical &lt;a href="http://okasaki.blogspot.com/2008/03/creativity.html"&gt;creativity&lt;/a&gt; plays a large role in the movie.  One comment was especially intriguing. (Minor spoiler ahead.)  In describing the process of solving a particularly difficult problem, one character says, &amp;ldquo;It was like...connecting dots.  Some nights I...I could connect three or four of them.  And some nights they'd be really far apart.  I'd have no idea how to get to the next one, if there was the next one.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;This description rings both true and false for me.  The true part is &lt;i&gt;I'd have no idea how to get to the next one, if there was the next one.&lt;/i&gt;  This nicely summarizes what it's like to work on a hard problem.  You don't know what to do next, and you're not sure that a solution even exists.&lt;/p&gt;
&lt;p&gt;But the connecting dots part doesn't feel right.  It makes the process sound linear, when the reality is anything but.  In my experience, the really hard problems&amp;#8212;the ones that require the most creativity&amp;#8212;are most often solved by &lt;i&gt;epiphany&lt;/i&gt;, by having the whole solution burst into your head, seemingly in an instant.  That's when the connecting dots part happens, but it all happens at once, not a few a time.&lt;/p&gt;
&lt;p&gt;Of course, the catch is that epiphany can't be forced.  I'm reminded of the old joke about the lottery.  A man prays fervently every night, &amp;ldquo;Please, Lord, let me win the lottery tomorrow.&amp;rdquo;  After twenty years, a heavenly voice responds, &amp;ldquo;Would you buy a ticket already!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;No, you can't just sit around waiting for an epiphany to happen.  Epiphanies are hard work!  &lt;a href="http://en.wikipedia.org/wiki/TANSTAAFL"&gt;TANSTAAFL.&lt;/a&gt;  So, how do you go about searching for epiphany?  Every epiphany I've ever had has been the result of a two-pronged effort.&lt;/p&gt;
&lt;p&gt;The first prong is building up &lt;a href="http://en.wikipedia.org/wiki/Sweat_equity"&gt;sweat equity&lt;/a&gt;.  I thoroughly explore the space around the problem, playing with the problem from many different angles.  Of course, I'm actively trying to solve the problem during this time, because I might get lucky and stumble across a solution.  But I don't worry too much if I don't seem to be getting anywhere.  This part of the process is not so much about connecting the dots as about building lots and lots (and lots) of &lt;i&gt;potential&lt;/i&gt; connections.&lt;/p&gt;
&lt;p&gt;The second prong is staying alert. That's easy to say, but really hard to do over long periods of time.  Eventually, I hope, some stray thought or some environmental trigger will start a cascade, where some subset of those potential connections will become actual connections, creating a path to the solution.  Sometimes this happens when you're relaxed and your mind is drifting, such as in the shower or while driving.  I remember once in grad school trying all afternoon to track down a bug.  That night my wife and I went over to a friend's house for dinner.  Everybody was shocked when, in the middle of beef stroganoff, I suddenly shouted out, &amp;ldquo;That's it!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Other times the epiphany can happen while you're actively working on something else.  For example, the key insight behind &lt;a href="http://okasaki.blogspot.com/2008/03/what-heck-is-math-trade.html"&gt;TradeMaximizer&lt;/a&gt; came while I was trying to put together a homework for my Algorithms class.  I had been working off and on for weeks trying to find cycles in the trade graph.  But I had set that aside and was coming up with homework problems, when I stumbled across a stray comment that talked about converting a directed graph into a bipartite graph.  That sentence was enough to set off the chain reaction of connections and, within seconds, TradeMaximizer was born.&lt;/p&gt;
&lt;p&gt;Probably the most famous story about scientific epiphany is that of &lt;a href="http://en.wikipedia.org/wiki/Eureka_%28word%29#Archimedes"&gt;Archimedes' bath&lt;/a&gt;.  Funny story: Shortly after announcing TradeMaximizer to the math trade community on BoardGameGeek, I received a peevish email from another BoardGameGeek user who thought he also had a solution.  He described how he had come to BoardGameGeek, eager to share his discovery, only to find my announcement first.  He complained &amp;ldquo;Argh!  Way to shout &amp;lsquo;Eureka!&amp;rsquo; while Archimedes is drying himself off!&amp;rdquo;  (The other solution turned out to be bogus.)&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7481880971245369481?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7481880971245369481/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7481880971245369481' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7481880971245369481'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7481880971245369481'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/07/in-search-of-epiphany.html' title='In search of epiphany'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7530267096920590688</id><published>2008-07-16T23:27:00.001-04:00</published><updated>2008-07-31T09:41:31.999-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Games for Programmers: Black Vienna</title><content type='html'>&lt;p&gt;&lt;i&gt;The next in an irregular series of board game recommendations for programmers. Of course, you don't have to be a programmer to enjoy these games, but if you are a programmer, then I think there's a pretty good chance that you'll like them.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;O frabjous day!&lt;/p&gt;
&lt;p&gt;My favorite deduction game, &lt;a href="http://www.boardgamegeek.com/game/756"&gt;Black Vienna&lt;/a&gt;, has long been out of print, but now you can give it a try online, thanks to the efforts of Greg Aleknevicus.  Go check out &lt;a href="http://www.aleknevicus.com/bv/"&gt;Black Vienna Online&lt;/a&gt;.  It's free and easy to use.  The user interface isn't going to win any awards, but it gets the job done.  I'm thrilled that this game can now reach a wider audience.&lt;/p&gt;
&lt;p&gt;Most deduction games are for two players, but Black Vienna handles three to six players.  Your goal is to figure out the members of the infamous &amp;ldquo;Black Vienna&amp;rdquo; gang.  There are 27 suspect cards, labeled A-Z and &amp;Ouml;.  At the beginning of the game, three of these cards are chosen randomly and set aside.  Those are the members of the gang.&lt;/p&gt;
&lt;p&gt;The remaining 24 suspect cards are dealt out evenly to the players.  (With 5 players, one of the players gets only 4 cards.)  These are the cards of suspects for whom you can provide alibis.&lt;/p&gt;
&lt;p&gt;On your turn you conduct an investigation.  There is a pool of available investigation cards, each showing three suspects.  You choose one of the available investigation cards and place it in front of another player.  That player marks the card with plastic chips, according to how many of the suspects are in her hand.  For example, if I have the cards BGMTXY and somebody plays the BQT card on me, I would mark it with two chips (for the B and the T).  Other players would then know that I had two of the three suspects, but not necessarily which ones.&lt;/p&gt;
&lt;p&gt;The turn then passes to the player who was just investigated.&lt;/p&gt;
&lt;p&gt;One nice thing about Black Vienna as a game is that every player is involved on every turn.  Even if you are not actively part of the investigation, you still need to update your information with the results of the investigation, and follow any chains of deductions to their conclusions.&lt;/p&gt;
&lt;h3&gt;Example Deductions&lt;/h3&gt;
&lt;p&gt;Some deductions are obvious.  For example, if I played two chips on the BQT card, and you have the Q card in your hand, then you know that I have the B and the T.  Other deductions are less obvious.  Here's an actual example from a recent game.  Call the other players Caitlin, Monica, Drew, and Dom.&lt;/p&gt;
&lt;p&gt;Monica played one chip on GPX, but I had the X, so I knew that she had either G or P (but not both).   Similarly, she also played one chip on DHR, but I knew Dom had the R, so Monica had either D or H.  Finally, she played two chips on LNV.&lt;/p&gt;
&lt;p&gt;Drew played one chip on DVY and zero chips on F&amp;Ouml;Y, so he had either D or V.  Between Drew and Monica, they had at least 4 of the 5 cards DHLNV and at least 5 of the 7 cards DGHLNPV (possibly more if Drew had any of GHLNP).&lt;/p&gt;
&lt;p&gt;Meanwhile, I knew all but two of Caitlin's cards.  The only possibilities for those last two cards were DGHLNPV.  Monica and Drew together had at least 5 of those 7 cards, so Monica, Drew, and Caitlin together must have all 7.&lt;/p&gt;
&lt;p&gt;This tells me that none of these 7 cards are in the gang, and none of these 7 cards are in Dom's hand.  It also tells me that Drew does not have any of GHLNP.&lt;/p&gt;
&lt;p&gt;Finally, I can be more specific about Caitlin's cards.  One of her two cards is G or P, and the other is one of DHLNV.&lt;/p&gt;
&lt;h3&gt;Online Play&lt;/h3&gt;
&lt;p&gt;The online implementation is asynchronous.  You do not need to be logged in at the same time as other players.  Instead, the system emails you whenever a turn is taken with the results of the investigation.  When it is your turn, you can log on and take your turn at your leisure.  This means that a 45-minute face-to-face game can take days or even weeks when played online, but it also means that you can play the game with odd minutes here and there, instead of having to carve out a solid chunk of time.  An additional benefit is that it is easy to play with friends in different time zones.  For example, I frequently play with friends on the other side of the country.&lt;/p&gt;
&lt;p&gt;However, the greatest benefit of the online implementation is that it does away with the greatest weakness of face-to-face play&amp;#8212;player errors.  Not errors in deductions, which would be your own fault and would only affect you, but errors in answering investigations.  If a player carelessly puts out, say, one chip when he should have put out two chips, it ruins the game for everyone.  Even if the player notices the error a few turns later and tries to correct it, it's far too late.  By then, the other players have already updated their notes with deductions made from the faulty answer, and typically have no way of backing out of those deductions.&lt;/p&gt;
&lt;p&gt;If you want to give Black Vienna a try, see the &lt;a href="http://www.aleknevicus.com/bv/rules.php"&gt;detailed rules of the game&lt;/a&gt; and the &lt;a href="http://www.aleknevicus.com/bv/about.php"&gt;instructions for the online interface&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Addendum:&lt;/b&gt; I've played in several three-player games recently.  It's ok with that number, but I think it's significantly better with four or five players.  (I haven't tried six yet.)  With three players, the deductions are less interesting, and there is a greater chance for one player to get lucky.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7530267096920590688?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7530267096920590688/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7530267096920590688' title='20 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7530267096920590688'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7530267096920590688'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/07/games-for-programmers-black-vienna.html' title='Games for Programmers: Black Vienna'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>20</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5015274343282261603</id><published>2008-07-08T23:39:00.001-04:00</published><updated>2008-07-08T23:40:07.952-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='algorithm in pictures'/><title type='text'>Breadth-First Numbering: An Algorithm in Pictures</title><content type='html'>&lt;p&gt;I've always enjoyed the mathematical tradition of &amp;ldquo;proofs without words&amp;rdquo;, so I wanted to see if something similar could be done with an algorithm.  Of course, an algorithm is typically more complicated than a mathematical identity, so it's not surprising that an algorithm typically can't be captured in a single picture.  Instead, I've found the idea of a  &lt;a href="http://en.wikipedia.org/wiki/Commutative_diagram"&gt;commutative diagram&lt;/a&gt; to be a useful pictorial shorthand, where the short way around the diagram gives a high-level view of the operation, and the long way around gives more detail.  Here is an attempt to describe my breadth-first numbering algorithm from ICFP 2000 using this idea.&lt;/p&gt;

&lt;h3&gt;Wanted&lt;/h3&gt;
&lt;a href="http://bp0.blogger.com/_HOXl0OgNHo0/SHQmEL2eWfI/AAAAAAAAABM/jFOGqrGhqug/s1600-h/bfn-wanted.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp0.blogger.com/_HOXl0OgNHo0/SHQmEL2eWfI/AAAAAAAAABM/jFOGqrGhqug/s400/bfn-wanted.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5220839721371851250" /&gt;&lt;/a&gt;

&lt;h3&gt;Rules&lt;/h3&gt;
&lt;a href="http://bp3.blogger.com/_HOXl0OgNHo0/SHQx8xLuIKI/AAAAAAAAABk/t19XAekguuw/s1600-h/bfn-rules.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp3.blogger.com/_HOXl0OgNHo0/SHQx8xLuIKI/AAAAAAAAABk/t19XAekguuw/s400/bfn-rules.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5220852788093657250" /&gt;&lt;/a&gt;

&lt;h3&gt;Example&lt;/h3&gt;
&lt;a href="http://bp2.blogger.com/_HOXl0OgNHo0/SHQyHKv0J2I/AAAAAAAAABs/pWKezOw1U8A/s1600-h/bfn-example.jpg"&gt;&lt;img style="cursor:pointer; cursor:hand;" src="http://bp2.blogger.com/_HOXl0OgNHo0/SHQyHKv0J2I/AAAAAAAAABs/pWKezOw1U8A/s400/bfn-example.jpg" border="0" alt=""id="BLOGGER_PHOTO_ID_5220852966754625378" /&gt;&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5015274343282261603?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5015274343282261603/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5015274343282261603' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5015274343282261603'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5015274343282261603'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/07/breadth-first-numbering-algorithm-in.html' title='Breadth-First Numbering: An Algorithm in Pictures'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://bp0.blogger.com/_HOXl0OgNHo0/SHQmEL2eWfI/AAAAAAAAABM/jFOGqrGhqug/s72-c/bfn-wanted.jpg' height='72' width='72'/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5064063170271533901</id><published>2008-07-02T20:35:00.017-04:00</published><updated>2008-07-02T21:06:54.345-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='Ada'/><category scheme='http://www.blogger.com/atom/ns#' term='recursion'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Functional Programming in...Ada?</title><content type='html'>&lt;p&gt;Ada is not the first language that comes to mind when you want to do functional programming.  (&lt;i&gt;You in the back, stop laughing!&lt;/i&gt;) Why, with excellent functional programming languages like Haskell or ML easily available, would I choose to do a functional programming project in Ada?  (&lt;i&gt;I CAN STILL HEAR YOU LAUGHING!&lt;/i&gt;) Partly because we use Ada in some courses at our institution, and I wanted a library that could help in teaching recursion to novices.  But, honestly, mostly I just wanted to see if it could be done.&lt;/p&gt;

&lt;blockquote style="width: 65%; font: bold 1.0em Arial, Helvetica, Verdana, sans-serif; border: 1pt solid black; padding: 0.5ex;"&gt;&amp;ldquo;It's like this fellow I knew in El Paso. One day, he just took all his clothes off and jumped in a mess of cactus. I asked him that same question, &amp;lsquo;Why?&amp;rsquo;...He said, &amp;lsquo;It seemed like a good idea at the time.&amp;rsquo;&amp;rdquo; &lt;div style="textalign:right;"&gt;&amp;ndash; Steve McQueen, &lt;i&gt;The Magnificent Seven&lt;/i&gt;&lt;/div&gt;&lt;/blockquote&gt;

&lt;p&gt;Somewhat to my surprise, functional programming actually works reasonably well in Ada.  You wouldn't want to program a large system this way, but small-scale projects are quite possible, albeit much more verbose than functional programmers are used to.&lt;/p&gt;

&lt;h3&gt;Instrumenting recursive functions&lt;/h3&gt;
&lt;p&gt;My application is going to be a library for instrumenting recursive functions.  I want to be able to take a recursive function and run it with different combinations of &lt;i&gt;monitors&lt;/i&gt;.  Each monitor executes a little bit of extra code every time the recursive function is called, including recursive calls.  Simple examples of useful monitors include counting the number of calls, or tracking the maximum call depth, or printing trace information on every call or return.  More complicated examples include adding memoization to a recursive function or automatically detecting when a function is stuck in an infinite recursion.&lt;/p&gt;

&lt;p&gt;Ideally, the library should be easy enough for students to use, but I'll settle for it being easy enough for instructors to use.&lt;/p&gt;

&lt;p&gt;Of course, there are many ways to design such a library.  I'm going to use a design based on ideas from functional programming.  The basic ideas have been folklore in the functional programming community for a long time.  For example, I remember doing something similar in SML in the early '90s.  Bruce McAdam wrote a nice &lt;a href="http://www.lfcs.inf.ed.ac.uk/reports/97/ECS-LFCS-97-375/ECS-LFCS-97-375.pdf"&gt;tech report&lt;/a&gt; describing these techniques in great detail.  The trick here is going to be figuring out how to implement this design in Ada.&lt;/p&gt;

&lt;p&gt;(Incidentally, if anybody has a truly object-oriented approach to solving the same problem, I'd be interested in seeing it.)&lt;/p&gt;

&lt;h3&gt;Preparing the recursive function&lt;/h3&gt;
&lt;p&gt;Without some kind of support for &lt;a href="http://en.wikipedia.org/wiki/Reflection_(computer_science)"&gt;reflection&lt;/a&gt;, it seems too much to hope that I'll be able to observe the recursive calls inside a recursive function.  Therefore, I'm willing to require some modifications to the recursive function, as long as those modifications are fairly straightforward.  However, I should only need to modify the function once, rather than every time I run it with a different monitor.&lt;/p&gt;

&lt;p&gt;Stealing an idea from functional programming called the &lt;a href="http://en.wikipedia.org/wiki/Fixed_point_combinator"&gt;Y combinator&lt;/a&gt;, I'll modify each recursive function to take an extra argument that is itself a function (or, more specifically, a pointer to a function).  The recursive function will call this passed-in function wherever it would normally call itself.  The passed-in function will eventually call the recursive function, but may run some other code first.&lt;/p&gt;

&lt;p&gt;Here's an example using the ever popular Fibonacci function.  The original recursive function might be written
&lt;pre&gt;
 function Fib(X : Integer) return integer is
 begin
   if X &lt;= 1 then
     return 1;
   else
     return Fib(X-1) + Fib(X-2);
   end if;
 end Fib;
&lt;/pre&gt;
Adding the extra argument and replacing the recursive calls with calls to the passed-in function yields
&lt;pre&gt;
 function Fib(&lt;font color="red"&gt;&lt;b&gt;Rec : access function(X : Integer)
                    return Integer;&lt;/b&gt;&lt;/font&gt;
              X : Integer) return integer is
 begin
   if X &lt;= 1 then
     return 1;
   else
     return &lt;font color="red"&gt;&lt;b&gt;Rec&lt;/b&gt;&lt;/font&gt;(X-1) + &lt;font color="red"&gt;&lt;b&gt;Rec&lt;/b&gt;&lt;/font&gt;(X-2);
   end if;
 end Fib;
&lt;/pre&gt;
where the changes are shown in red.  Note that &lt;tt&gt;access function(X :
Integer) return Integer&lt;/tt&gt; is the type of a pointer to a function
that takes an integer and returns an integer.  In the rest of this
post, I'll assume that the functions being instrumented always take an
integer and return an integer.  If I can get this to work at all, then
generalizing this to arbitrary argument and return types will be
trivial using Ada's notion of &lt;a href="http://en.wikipedia.org/wiki/Generic_programming#Generics_in_Ada"&gt;generics&lt;/a&gt;.

&lt;h3&gt;Running the recursive function&lt;/h3&gt;

&lt;p&gt;
Now, to simply run this function recursively &lt;i&gt;without&lt;/i&gt; attaching
a monitor, I'll call it with &lt;tt&gt;Run&lt;/tt&gt;, which is responsible for
&amp;ldquo;tying the knot&amp;rdquo; by somehow making the function call
itself.  The &lt;tt&gt;Run&lt;/tt&gt; function is written
&lt;pre&gt;
 function Run(Fun : ...&lt;i&gt;type to be filled in 
                       later&lt;/i&gt;...
              X : Integer) return Integer is
   function Rec(X : Integer) return Integer is
   begin
     Fun(Rec'Access, X);
   end Rec;
 begin
   return Rec(X);
 end Run;
&lt;/pre&gt;
Here, &lt;tt&gt;Fun&lt;/tt&gt; is a function like the modified &lt;tt&gt;Fib&lt;/tt&gt;
above.  &lt;tt&gt;Run&lt;/tt&gt; defines a local helper functon, &lt;tt&gt;Rec&lt;/tt&gt;,
that merely passes itself to &lt;tt&gt;Fun&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;
I would call this function by writing something like
&lt;pre&gt;
   ...Run(Fib'Access, 10)...
&lt;/pre&gt;
where &lt;tt&gt;Fib'Access&lt;/tt&gt; is Ada-speak for a pointer to the &lt;tt&gt;Fib&lt;/tt&gt; function.  This
calls &lt;tt&gt;Rec(10)&lt;/tt&gt;, which calls &lt;tt&gt;Fib(Rec'Access,10)&lt;/tt&gt;, which in turn calls &lt;tt&gt;Rec(9)&lt;/tt&gt;, which in turn calls &lt;tt&gt;Fib(Rec'Access,9)&lt;/tt&gt;, and so on.  Eventually, the whole thing returns 89, as expected.&lt;/p&gt;

&lt;p&gt;
I left out the type of &lt;tt&gt;Fun&lt;/tt&gt; above, because it starts to get
unwieldy.  I can figure out what this type should be by looking at the type of &lt;tt&gt;Fib&lt;/tt&gt;.  The full signature of &lt;tt&gt;Run&lt;/tt&gt; is
&lt;pre&gt;
 function Run(Fun : access function
                (Rec : access function(X:Integer)
                       return Integer;
                 X : Integer) return Integer;
              X : Integer) return Integer;
&lt;/pre&gt;

&lt;h3&gt;A small lie&lt;/h3&gt;

&lt;p&gt;
What I'd really &lt;i&gt;like&lt;/i&gt; to be able to do is define a type abbreviation
&lt;pre&gt;
 type Fun_Type is access function
   (Rec : access function(X:Integer)
          return Integer;
    X : Integer) return Integer;
&lt;/pre&gt;
and then write the signature of &lt;tt&gt;Run&lt;/tt&gt; as
&lt;pre&gt;
 function Run(Fun : Fun_Type; 
              X : Integer) return Integer;
&lt;/pre&gt;
Unfortunately, I can't.  Or rather, I can, but it turns out to be
useless.  The problem is that Ada is really paranoid about what you do
with pointers to functions.  In particular, it won't let a pointer to
a function match a named type if that function is defined in a
deeper lexical scope than the type definition.  This restriction does
not apply to so-called &lt;i&gt;anonymous access&lt;/i&gt; types, so I'm forced to
rewrite the entire type everywhere it's used rather than giving it a name and referring to the name.&lt;/p&gt;

&lt;p&gt;
However, to simplify the presentation, I'm going to &lt;i&gt;pretend&lt;/i&gt;
that I can use &lt;tt&gt;Fun_Type&lt;/tt&gt; as defined above.  Just remember
that, in the real implementation, every occurrence of
&lt;tt&gt;Fun_Type&lt;/tt&gt; needs to be replaced with the more verbose anonymous type.  I'll write &lt;tt&gt;&lt;i&gt;Fun_Type&lt;/i&gt;&lt;/tt&gt; in italics as a reminder that it's not the real code.

&lt;h3&gt;A simple monitor&lt;/h3&gt;

&lt;p&gt;
Now, here is a simple monitor that counts the number of calls to the recursive function, and prints out that number at the end.

&lt;pre&gt;
 function Count(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;;
                X : Integer) return Integer is

   Num_Calls : Integer := 0;

   function My_Fun
       (Rec : access function(X:Integer) 
              return Integer;
        X : Integer) return Integer is
   begin
     Num_Calls := Num_Calls + 1;
     return Fun(Rec,X);
   end My_Fun;

   Result : Integer := Run(My_Fun'Access,X);
 begin
   Put("Number of calls = ");
   Put(Num_Calls,0);
   New_Line;
   return Result;
 end Count;
&lt;/pre&gt;

&lt;p&gt;Now, when I call
&lt;pre&gt;
   Put( Count(Fib'Access,10) );
&lt;/pre&gt;
I get
&lt;pre&gt;
Number of calls = 177
         89
&lt;/pre&gt;
where the first line is printed by the monitor and the second line is printed by the external &lt;tt&gt;Put&lt;/tt&gt;.

&lt;p&gt;The &lt;tt&gt;Count&lt;/tt&gt; monitor creates a new function &lt;tt&gt;My_Fun&lt;/tt&gt; to give to &lt;tt&gt;Run&lt;/tt&gt;.  &lt;tt&gt;My_Fun&lt;/tt&gt; simply increments &lt;tt&gt;Num_Calls&lt;/tt&gt; and calls &lt;tt&gt;Fun&lt;/tt&gt;.  Now, every time &lt;tt&gt;Fun&lt;/tt&gt; makes a recursive call to &lt;tt&gt;Rec&lt;/tt&gt;, &lt;tt&gt;Rec&lt;/tt&gt; will call &lt;tt&gt;My_Fun&lt;/tt&gt;, which calls &lt;tt&gt;Fun&lt;/tt&gt;.  

&lt;p&gt;So basically, &lt;tt&gt;Count&lt;/tt&gt; &amp;ldquo;wraps&amp;rdquo; &lt;tt&gt;Fun&lt;/tt&gt; with
a little bit of code to increment the &lt;tt&gt;Num_Calls&lt;/tt&gt; variable, and
this code gets executed every time the &lt;tt&gt;Rec&lt;/tt&gt; function is
called.

&lt;p&gt;In addition, &lt;tt&gt;Count&lt;/tt&gt; does a little bit of work around the
top-level recursive call, namely initializing the &lt;tt&gt;Num_Calls&lt;/tt&gt;
variable to 0, and printing the number of calls at the end.

&lt;h3&gt;A memoization monitor&lt;/h3&gt;

&lt;p&gt;
Here's a more complicated monitor.  This one modifies the recursive
function to do &lt;a href="http://en.wikipedia.org/wiki/Memoization"&gt;memoization&lt;/a&gt; (first
cousin to &lt;a href="http://en.wikipedia.org/wiki/Dynamic_programming"&gt;dynamic
programming&lt;/a&gt;).  The idea is that, when a function is called
multiple times on the same arguments, you can save time by remembering
those arguments and the corresponding results.  Then when the function
is called with arguments you have seen before, you can simply return
the stored result, instead of recomputing it.&lt;/p&gt;

&lt;pre&gt;
 function Memoize(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;; 
                  X : Integer) return Integer is

   Results : array (0..X) OF Integer;
   Ready   : array (0..X) OF Boolean 
               := (others =&gt; False);

   function My_Fun
       (Rec : access function(X:Integer) 
              return Integer;
        X : Integer) return Integer is
   begin
     if not Ready(X) then
       Results(X) := Fun(Rec,X);
       Ready(X) := True;
     end if;
     return Results(X);
   end My_Fun;

 begin
   return Run(My_Fun'Access,X);
 end Memoize;
&lt;/pre&gt;
The difference can be dramatic.
&lt;pre&gt;
   ...Memoize(Fib'Access, 30)...
&lt;/pre&gt;
executes the body of &lt;tt&gt;Fib&lt;/tt&gt; a total of 31 times, whereas
&lt;pre&gt;
   ...Run(Fib'Access, 30)...
&lt;/pre&gt;
executes the body of &lt;tt&gt;Fib&lt;/tt&gt; almost 2.7 &lt;i&gt;million&lt;/i&gt; times (2692537 times, to be exact).

&lt;p&gt;
I made an assumption above that, if the original argument was X, then the range of possible arguments in all the calls is 0..X.  This is good enough to illustrate the idea, but a more general implementation might be parameterized by the bounds to use, or by a function that calculates those bounds from the original X.&lt;/p&gt;

&lt;h3&gt;Multiple monitors&lt;/h3&gt;

&lt;p&gt;How did I know above that &lt;tt&gt;Run&lt;/tt&gt; executes the body of
&lt;tt&gt;Fib&lt;/tt&gt; 2692537 times?  By running &lt;tt&gt;Fib&lt;/tt&gt; with the
&lt;tt&gt;Count&lt;/tt&gt; monitor.  How did I know that &lt;tt&gt;Memoize&lt;/tt&gt; executes
the body of &lt;tt&gt;Fib&lt;/tt&gt; 31 times?  By running &lt;tt&gt;Fib&lt;/tt&gt; with both the 
&lt;tt&gt;Memoize&lt;/tt&gt; and &lt;tt&gt;Count&lt;/tt&gt; monitors together.&lt;/p&gt;

&lt;p&gt;Except that, as currently written, the &lt;tt&gt;Memoize&lt;/tt&gt; and
&lt;tt&gt;Count&lt;/tt&gt; monitors &lt;i&gt;can't&lt;/i&gt; be used together.  I can run &lt;tt&gt;Fib&lt;/tt&gt; with one or the other, but not both simultaneously.

&lt;p&gt;What I want is a way to layer one monitor on top of another,
building arbitrary stacks of monitors.  The clues to how to do this are already in the current implementations of &lt;tt&gt;Memoize&lt;/tt&gt; and &lt;tt&gt;Count&lt;/tt&gt;.&lt;/p&gt;

&lt;p&gt;Notice that both &lt;tt&gt;Memoize&lt;/tt&gt; and &lt;tt&gt;Count&lt;/tt&gt; have the same
interface as &lt;tt&gt;Run&lt;/tt&gt;.  In other words, a monitor is an
alternative run function that adds some extra machinery to the basic
&lt;tt&gt;Run&lt;/tt&gt;.  Further, notice that both &lt;tt&gt;Memoize&lt;/tt&gt; and
&lt;tt&gt;Count&lt;/tt&gt; build a &lt;tt&gt;My_Fun&lt;/tt&gt; function by wrapping some extra
code around &lt;tt&gt;Fun&lt;/tt&gt; and then run &lt;tt&gt;My_Fun&lt;/tt&gt; using the
&lt;tt&gt;Run&lt;/tt&gt; function.  The key insight is that we can parameterize &lt;tt&gt;Memoize&lt;/tt&gt; and &lt;tt&gt;Count&lt;/tt&gt; by which run function to use for running &lt;tt&gt;My_Fun&lt;/tt&gt;.  That might be the basic &lt;tt&gt;Run&lt;/tt&gt; function, but it might also be a run function corresponding to a different monitor.&lt;/p&gt;

&lt;p&gt;
To achieve this parameterization, I'll use generics instead of passing function pointers.  The existing definitions of &lt;tt&gt;Memoize&lt;/tt&gt; and &lt;tt&gt;Count&lt;/tt&gt; will still work, but they need to be preceded by additional code to take a run function as a generic parameter.  For example,
&lt;pre&gt;
 &lt;font color="red"&gt;generic
   with function Run(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;; 
                     X : Integer) return Integer;
 function Count(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;; 
                X : Integer) return Integer;&lt;/font&gt;

 function Count(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;; 
                X : Integer) return Integer is
   ...
     ... Run(My_Fun'Access, X);
   ...
&lt;/pre&gt;
The new parts are in red.  I didn't change the existing code of
&lt;tt&gt;Count&lt;/tt&gt; at all, but now the call to &lt;tt&gt;Run&lt;/tt&gt; in the body of
&lt;tt&gt;Count&lt;/tt&gt; refers to the run function passed in as a generic
parameter.

&lt;p&gt;
Using a monitor is now a two-stage process, first instantiating the generic function to create the desired run function, and then calling that run function.  For example,
&lt;pre&gt;
 function C_Run is new Count(Run);
 function MC_Run is new Memoize(C_Run);

 ...MC_Run(Fib'Access, 30)...
&lt;/pre&gt;
Notice that the basic &lt;tt&gt;Run&lt;/tt&gt; function is always used in the first instantiation, where it serves as the base of the stack of monitors.&lt;/p&gt;

&lt;p&gt;
But wait!  Something strange is happening here.  This program displays 59 calls, not 31 calls as expected.  However, if we layer the monitors in the opposite order
&lt;pre&gt;
 function M_Run is new Memoize(Run);
 function CM_Run is new Count(M_Run);

 ...MC_Run(Fib'Access, 30)...
&lt;/pre&gt;
then we get the 31 calls.&lt;/p&gt;

&lt;p&gt;
It's really a question of when the memoization code checks for a
repeated argument relative to when the counting code increments
the counter.  If the memoization check happens before the increment,
we get 31 calls.  If the memoization check happens after the
increment, we get 59 calls.  Either way, the body of the original
&lt;tt&gt;Fib&lt;/tt&gt; function is only executed 31 times.
&lt;/p&gt;

&lt;p&gt;
And that's it, really.  There's still a lot of grunt work involved in
fleshing out a complete, robust library, but all the important design
decisions have already been made.  Implementing a wide variety of monitors is
fairly easy using &lt;tt&gt;Count&lt;/tt&gt; and &lt;tt&gt;Memoize&lt;/tt&gt; as templates.
&lt;/p&gt;

&lt;h3&gt;Generics vs function pointers&lt;/h3&gt;

&lt;p&gt;
One aspect of this design deserves a little more discussion.  I'm
mixing two different styles of passing functions as arguments, using
generics in some places and function pointers in other places.  Why
not just use one style consistently?  Because the two styles of
passing around functions have different strengths and weaknesses.
&lt;/p&gt;

&lt;p&gt;
One major difference is that generics work much better than function
pointers when you want to &lt;i&gt;return&lt;/i&gt; a function.  For example, the
generic &lt;tt&gt;Count&lt;/tt&gt; monitor takes a run function and returns a run
function.  It's easy to imagine writing &lt;tt&gt;Count&lt;/tt&gt; as
&lt;pre&gt;
 function Count(Run : &lt;i&gt;Run_Type&lt;/i&gt;) 
                return &lt;i&gt;Run_Type&lt;/i&gt; is ...
&lt;/pre&gt;
where &lt;tt&gt;&lt;i&gt;Run_Type&lt;/i&gt;&lt;/tt&gt; is the appropriate &lt;tt&gt;access function&lt;/tt&gt; type.  But, in practice, this doesn't work because Ada lacks
&lt;a href="http://en.wikipedia.org/wiki/Closure_%28computer_science%29"&gt;closures&lt;/a&gt;.  The natural way to write this would be
&lt;pre&gt;
 function Count(Run : &lt;i&gt;Run_Type&lt;/i&gt;) return &lt;i&gt;Run_Type&lt;/i&gt; is

   function My_Run(Fun : &lt;i&gt;Fun_Type&lt;/i&gt;; 
                   X : Integer) return Integer is
     ...

 begin
   return My_Run'Access;
 end Count;
&lt;/pre&gt;
but you can't return &lt;tt&gt;My_Run'Access&lt;/tt&gt; because &lt;tt&gt;My_Run&lt;/tt&gt; goes away as soon as &lt;tt&gt;Count&lt;/tt&gt; returns.&lt;/p&gt;

&lt;p&gt;
Note that it is possible to get around this restriction against
returning function pointers by re-writing strategic code fragments in
&lt;a href="http://en.wikipedia.org/wiki/Continuation_passing_style"&gt;continuation-passing style&lt;/a&gt;, so that the function pointers in question can be passed to
a continuation instead of returned.  This works fine on a small scale,
but quickly blows the runtime stack when attempted on a large scale.&lt;/p&gt;

&lt;p&gt;
A second major difference is that it is easier to write third-order
(or even higher-order) functions using function pointers than
using generics.  A first-order function takes an ordinary value as an
argument.  A second-order function takes a first-order function as an
argument.  A third-order function takes a second-order function as an
argument, and so on.  Now, consider a monitor like &lt;tt&gt;Count&lt;/tt&gt;.
&lt;tt&gt;Count&lt;/tt&gt; takes a &lt;tt&gt;Run&lt;/tt&gt; function, which takes a
&lt;tt&gt;Fun&lt;/tt&gt; function, which takes a &lt;tt&gt;Rec&lt;/tt&gt; function, so
&lt;tt&gt;Count&lt;/tt&gt; is fourth-order!&lt;/p&gt;

&lt;p&gt;
Currently, I pass the &lt;tt&gt;Run&lt;/tt&gt; functions using generics, but the
&lt;tt&gt;Fun&lt;/tt&gt; functions using function pointers.  (Ignore the
&lt;tt&gt;Rec&lt;/tt&gt; functions for now.)  Suppose I wanted to pass both
&lt;tt&gt;Run&lt;/tt&gt; functions and &lt;tt&gt;Fun&lt;/tt&gt; functions using generics.
This would mean that each &lt;tt&gt;Run&lt;/tt&gt; function would take its
&lt;tt&gt;Fun&lt;/tt&gt; function as a generic parameter.  But &lt;i&gt;that&lt;/i&gt; means
that, when we pass a &lt;tt&gt;Run&lt;/tt&gt; function to a monitor like
&lt;tt&gt;Count&lt;/tt&gt;, we need to pass it as a generic function.  In other
words, &lt;tt&gt;Count&lt;/tt&gt; would need to be a generic function that takes a
generic function as an argument.  That's not allowed in Ada.  Or, more
truthfully, it is sometimes allowed, but it's extremely painful.
&lt;/p&gt;

&lt;p&gt;
In Ada, a generic function can neither take a generic function as an
argument nor return a generic function as a result.  However, a
package can contain generic components, so you can sometimes fake it
wrapping the argument or result in a package.  For example, you can
fake a generic function that returns a generic function by writing a
generic package that contains a generic function as a component.
&lt;/p&gt;

&lt;p&gt;
In a limited way, you can do the same thing in the other direction.
If you want a generic function to take a generic function as an
argument, you can fake it by wrapping the argument in a package, so
that the outer generic function takes a package (which contains a
generic function as a component).  The catch is that you can't
instantiate the outer generic function with just any old package
meeting a certain specification, but only with packages that are
themselves instantiations of a single generic package.  Making all
that work is an exercise in pain that I leave to the most masochistic
of readers.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5064063170271533901?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5064063170271533901/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5064063170271533901' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5064063170271533901'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5064063170271533901'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/07/functional-programming-inada.html' title='Functional Programming in...Ada?'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-8110986132276608812</id><published>2008-06-04T10:41:00.000-04:00</published><updated>2008-06-04T10:41:32.485-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><title type='text'>No Applause, Please</title><content type='html'>&lt;p&gt;My school recently had its graduation.  This year's graduating seniors (the computer science majors, anyway) are particularly memorable for me.  For one thing, I had more success than usual in luring them into playing board games, especially Race for the Galaxy, Attika, RoboRally, and Ricochet Robots.&lt;/p&gt;
&lt;p&gt;However, this group also stood out for a classroom behavior that I'm not used to&amp;#8212;applause.&lt;/p&gt;
&lt;p&gt;It started in Algorithms.  In this course, when a homework is due, I usually have several students present their solutions.  If the student solutions have not illustrated a point that I wanted to make, I will then present my solution, which is usually more elegant, and sometimes significantly more efficient as well.  My goal in doing this is not to show them up, or to say &amp;ldquo;hey, dummy, this is what you should have written&amp;rdquo;, but rather to help them catch a glimpse of the beauty I see in an elegant algorithm, to inspire them with what is possible.  (I do worry sometimes that fragile personalities might find the experience demoralizing, rather than inspiring.)&lt;/p&gt;
&lt;p&gt;Last year, after presenting such a solution, I was very surprised when one particular student started clapping.  He continued to do this in future weeks, and eventually pressured other students into joining him.&lt;/p&gt;
&lt;p&gt;At first, I was taken aback, but over time, I got more and more frustrated.  It felt like the applause was saying &amp;ldquo;this is so far beyond me that I could never hope to match it&amp;rdquo;, whereas I was hoping for a reaction more like &amp;ldquo;this may be beyond me right now, but, by golly, if I work at it, I'll be able to do that someday&amp;rdquo;.  Eventually, I snapped, &amp;ldquo;C'mon, I'm not trying to impress you with &lt;i&gt;my&lt;/i&gt; brilliance.  I want you to impress me with &lt;i&gt;your&lt;/i&gt; brilliance!&amp;rdquo;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-8110986132276608812?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/8110986132276608812/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=8110986132276608812' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8110986132276608812'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8110986132276608812'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/06/no-applause-please.html' title='No Applause, Please'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5386857757656866005</id><published>2008-05-23T13:26:00.000-04:00</published><updated>2008-05-23T13:26:31.868-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='kids'/><category scheme='http://www.blogger.com/atom/ns#' term='math'/><title type='text'>A Story About Odd and Even Numbers</title><content type='html'>&lt;p&gt;&lt;i&gt;This is a story my son and I wrote together when he was four.  He came up with the basic story.  I helped with the English and with the turtle character.&lt;/i&gt;&lt;/p&gt;
&lt;h3 align="center"&gt;The Seven Jellybeans&lt;/h3&gt;
&lt;p&gt;Once upon a time, there was a lizard and a snake who were friends.  They played together and had fun everyday until one day, the lizard's daddy gave them a bag of jellybeans to share.&lt;/p&gt;
&lt;p&gt;In the bag, there were seven jellybeans.  The lizard divided the jellybeans into two piles.  His pile had 5 jellybeans, and the snake's pile had 2 jellybeans.&lt;/p&gt;
&lt;p&gt;The snake said, &amp;ldquo;Wait a minute. That's not fair.  You have more jellybeans than I do.  You'd better give me one more jellybean.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So the lizard gave the snake one more jellybean.  And now the lizard had 4 jellybeans, and the snake had 3 jellybeans.  The snake said, &amp;ldquo;Hey, that's still not fair.  You still have more jellybeans than I do.  You'd better give me one more jellybean.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So the lizard gave the snake one more jellybean.  And now the lizard had 3 jellybeans, and the snake had 4 jellybeans.  Now the snake was happy, but the lizard said, &amp;ldquo;Hey, that's not fair.  Now you have more jellybeans than I do.  You'd better give me back one jellybean.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;So the snake gave the lizard back one jellybean.  And now the lizard had 4 jellybeans, and the snake had 3 jellybeans.  The snake said, &amp;ldquo;Hey, what happened?  Now you have more jellybeans again.  You must have cheated!&amp;rdquo;&lt;/p&gt;
&lt;p&gt;And then the lizard and the snake began to fight.&lt;/p&gt;
&lt;p&gt;While they were fighting, their friend the turtle walked by.  He asked them why they were fighting, and the lizard and the snake told him.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Hmm,&amp;rdquo; said the turtle.  &amp;ldquo;If I solve your problem, will you give me one jellybean?&amp;rdquo;&lt;/p&gt;
&lt;p&gt;The lizard and the snake didn't want to share their jellybeans, but they didn't want to fight either, so they agreed.&lt;/p&gt;
&lt;p&gt;The turtle slowly ate one jellybean.  Then he turned around and began to walk away.&lt;/p&gt;
&lt;p&gt;&amp;ldquo;Wait a minute,"&amp;rdquo; shouted the lizard and the snake together.  &amp;ldquo;You said that if we gave you one jellybean, you would solve our problem.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;&amp;ldquo;I just did,&amp;rdquo; said the turtle as he continued to walk away.&lt;/p&gt;
&lt;p&gt;The lizard and the snake looked at their piles of jellybeans.  The lizard had 3 jellybeans and the snake had 3 jellybeans.  They happily ate their jellybeans, and soon all of the jellybeans disappeared.&lt;/p&gt;
&lt;p&gt;The next day, the snake's mommy gave them a box of raisins to share.  The lizard and the snake opened the box and counted seven raisins.  &amp;ldquo;Oh no,&amp;rdquo; they said, and they went to look for the turtle to give him one of their raisins.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5386857757656866005?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5386857757656866005/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5386857757656866005' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5386857757656866005'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5386857757656866005'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/05/story-about-odd-and-even-numbers.html' title='A Story About Odd and Even Numbers'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-1645424467616349700</id><published>2008-05-20T11:44:00.000-04:00</published><updated>2008-05-20T11:44:52.174-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Designing a Data Structure</title><content type='html'>&lt;p&gt;Students are rarely given an opportunity to design an algorithmically non-trivial data structure.  We might give them a scenario and ask them to design how to represent the data, but that design decision is usually something like choosing between a hash table or an array or a linked-structure.  Once that high level decision is made, there is very little left to design.&lt;/p&gt;
&lt;p&gt;One reason for this is that many data structures depend on non-obvious invariants.  Most students are pretty shaky on the whole idea of invariants to begin with; they're never going to spontaneously come up with something like the rules describing &lt;a href="http://en.wikipedia.org/wiki/Red_black_tree"&gt;red-black trees&lt;/a&gt; or &lt;a href="http://en.wikipedia.org/wiki/Leftist_heap"&gt;leftist heaps&lt;/a&gt;.  With these kinds of data structures, we basically present the finished product and possibly ask them to implement and/or analyze the data structure, but we never ask them to design something like that.&lt;/p&gt;
&lt;p&gt;For several years, I've been trying to give students a taste of real data structure design, using the sample priority queue below.  I usually do this in class, where I can help steer them with gentle questioning, but I try very hard to make sure that &lt;i&gt;they&lt;/i&gt; come up with the important parts.&lt;/p&gt;
&lt;p&gt;I always do this at some point after the students have studied &lt;a href="http://en.wikipedia.org/wiki/Binary_heap"&gt;binary heaps&lt;/a&gt; (the kind typically used in heapsort).  I briefly review the priority queue operations binary heaps support (&lt;tt&gt;insert&lt;/tt&gt;, &lt;tt&gt;findMin&lt;/tt&gt;, and &lt;tt&gt;deleteMin&lt;/tt&gt;) and the basic idea of heap-ordered trees.  Then, I introduce the idea of &lt;i&gt;merging&lt;/i&gt; two heaps.  With binary heaps, this takes O(N) time, or even O(N log N) time, if done naively.  I ask them to design a new data structure to support merging in O(log n) time, while the other priority queue operations run in the same bounds as for binary heaps, O(1) for &lt;tt&gt;findMin&lt;/tt&gt; and O(log N) for &lt;tt&gt;insert&lt;/tt&gt; and &lt;tt&gt;deleteMin&lt;/tt&gt;.  I suggest that they use heap-ordered binary trees (real trees, rather than simulating trees using arrays like in binary heaps), but that they can modify these trees in any way that is helpful.&lt;/p&gt;
&lt;p&gt;With heap-ordered trees, &lt;tt&gt;findMin&lt;/tt&gt; is trivial&amp;#8212;it just returns the root.  To get their creative juices flowing, I then ask them to implement &lt;tt&gt;insert&lt;/tt&gt; and &lt;tt&gt;deleteMin&lt;/tt&gt; in terms of &lt;tt&gt;merge&lt;/tt&gt;.  This is also pretty easy: &lt;tt&gt;insert&lt;/tt&gt; creates a new singleton tree and calls &lt;tt&gt;merge&lt;/tt&gt;; &lt;tt&gt;deleteMin&lt;/tt&gt; discards the root and calls &lt;tt&gt;merge&lt;/tt&gt; on the two children of the root.  So the whole problem boils down to merging two trees efficiently.&lt;/p&gt;
&lt;p&gt;At this point, they usually flounder for a while, which is both ok and expected.  Some floundering is good.  Naturally, they'll start to get a little frustrated.  That, too, is ok and expected.  I just don't want them to get frustrated to the point where they shut down.  If the floundering continues too long without any progress, I'll ask them what they can tell immediately about the result tree by only looking at the roots of the input trees.  They'll quickly reply that the smaller of the two input roots becomes the root of the result tree.  So I have them draw that much of the result.  Depending on how things are going, I may further suggest that they draw two question marks for the children of the root in the result tree.&lt;/p&gt;
&lt;p&gt;Then the students will play for a while with how to fill in those question marks.  There are two slots for subtrees, but we have three subtrees that need to go in those slots: the two subtrees of the &amp;ldquo;winning&amp;rdquo; input root plus the  &amp;ldquo;losing&amp;rdquo; input root.  To fit three subtrees into two slots, naturally we need to merge two of them and leave one unchanged.  But which two should be merged?&lt;/p&gt;
&lt;p&gt;Usually, the students will begin with some fixed strategy, such as always merge the two subtrees of the winning root.  But it's easy to come up with counter-examples where such a strategy will take O(N) time.&lt;/p&gt;
&lt;p&gt;Once it becomes clear that some smarter strategy is required, the students focus on the question of which two of the three subtrees to merge.  Usually the next thing they try is merging the two subtrees with the smallest roots, which fails on the same kinds of counterexamples as before.&lt;/p&gt;
&lt;p&gt;Eventually, based on the intuition that &lt;tt&gt;merge&lt;/tt&gt; should run faster on small trees than on big trees, they try merging the two smallest trees.  This is always a good learning point about ambiguity, as we realize that there are three different possible meanings of &amp;ldquo;smallest&amp;rdquo;: the smallest root according to the ordering on keys, the smallest subtree according to number of nodes, or the smallest subtree according to the height of the subtrees.  We've already shot down the first one, but either of the other two will work, so I just go with whichever one the class prefers (usually smallest in number of nodes).&lt;/p&gt;
&lt;p&gt;One catch is that to efficiently compare sizes of subtrees (either number of nodes or height), we need to store the sizes at every node.  But that's easy to do by adding an extra field, and maintaining that size information is also easy, albeit slightly easier for number of nodes than for height.&lt;/p&gt;
&lt;p&gt;Typically, we don't have a lot of time left in class at this point, so I help them with the analysis, but it's easy to show that this design supports &lt;tt&gt;merge&lt;/tt&gt; in O(log N) time.  And there was much rejoicing!&lt;/p&gt;
&lt;p&gt;I call this data structure &lt;i&gt;maxiphobic heaps&lt;/i&gt; because of the way &lt;tt&gt;merge&lt;/tt&gt; avoids the biggest subtree at every step.  But I don't tell the students that name until after they've already come up with the design.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-1645424467616349700?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/1645424467616349700/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=1645424467616349700' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1645424467616349700'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1645424467616349700'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/05/designing-data-structure.html' title='Designing a Data Structure'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-1397938681668922314</id><published>2008-05-13T23:42:00.001-04:00</published><updated>2008-05-13T23:42:45.373-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computational thinking'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>On Balanced Trees and Car Insurance</title><content type='html'>&lt;p&gt;I usually don't teach our Data Structures course, but I often give a guest lecture about balanced binary search trees.  This comes right after they've learned about plain (unbalanced) binary search trees.  Often the previous lesson has ended with an illustration of what happens when values are inserted into the tree in sorted order.&lt;/p&gt;
&lt;p&gt;After reviewing that pathological case and how it can easily arise in practice, I dive in and explain how to keep the trees balanced.  In my case, I use red-black trees, but the exact choice of balancing scheme isn't critical to my point here.  At the end of class, I ask them how much faster they think the balanced trees are than the unbalanced trees.  They're shocked when I tell them that, most of the time, the balanced trees are &lt;i&gt;slower&lt;/i&gt; than the unbalanced trees.  As long as the data arrives in a reasonably random order, the plain binary search trees will actually end up being fairly balanced, without doing any extra work.  No mucking around with colors, no rotations&amp;#8212;of course the balanced trees are slower!&lt;/p&gt;
&lt;p&gt;So why bother?&lt;/p&gt;
&lt;p&gt;I tell them that it's like buying car insurance.  When you buy car insurance, you hope that you're just throwing your money away.  At the end of the year, if you haven't been in any accidents, you're happy to have wasted that money.  Why bother?  To protect against the uncommon case, to keep one unlucky event from turning into catastrophe.  You pay a little bit extra all the time to keep from paying a &lt;i&gt;lot&lt;/i&gt; extra every once in a while.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-1397938681668922314?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/1397938681668922314/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=1397938681668922314' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1397938681668922314'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1397938681668922314'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/05/on-balanced-trees-and-car-insurance.html' title='On Balanced Trees and Car Insurance'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7880837608298063768</id><published>2008-05-09T10:21:00.001-04:00</published><updated>2008-07-09T16:47:01.860-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='creativity'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><title type='text'>Barriers to Creativity</title><content type='html'>&lt;p&gt;Last week, I had lunch with some friends of mine, all college-level instructors.  I brought up the subject of creativity, which has been &lt;a href="http://okasaki.blogspot.com/2008/03/creativity.html"&gt;much on my mind lately&lt;/a&gt;.  Our discussion highlighted some of the barriers to creativity in education, especially from the side of the instructor.&lt;/p&gt;
&lt;h3&gt;Creativity means artsy, doesn't it?&lt;/h3&gt;
&lt;p&gt;At one point, I asked the chemistry professor in our group about the role of creativity in the first few college-level chemistry courses.  She was confused by the question at first, because she thought I meant something like writing poems about chemical reactions. (That reminds me of a scene in &lt;a href="http://en.wikipedia.org/wiki/Lois_McMaster_Bujold"&gt;Lois McMaster Bujold&lt;/a&gt;'s &lt;a href="http://www.amazon.com/Civil-Campaign-Lois-McMaster-Bujold/dp/0671578855"&gt;A Civil Campaign&lt;/a&gt;, in which a biochemist decides to rewrite the abstract to his dissertation in sonnet form.  &amp;ldquo;Can you think of a word to rhyme with &lt;i&gt;glyoxylate&lt;/i&gt;?&amp;rdquo;)&lt;/p&gt;
&lt;p&gt;Actually, I meant creativity in the sense of creative problem solving.  You know, the kind of thing &lt;a href="http://en.wikipedia.org/wiki/MacGyver"&gt;MacGyver&lt;/a&gt; might do with 2 aspirins, a tube of superglue, and a Diet Coke.  This misconception that creativity is the exclusive property of the arts is quite common.  If we the instructors of techncial courses don't think of what we do as creative, then we are hardly likely to portray our discipline in a way that encourages creativity.&lt;/p&gt;
&lt;p&gt;I'm using the word &amp;ldquo;arts&amp;rdquo; here to mean traditional arts like painting or poetry or music.  I happen to think an elegant algorithm can be quite beautiful and artistic, but I don't expect a layperson to recognize it as art.&lt;/p&gt;
&lt;h3&gt;Foundations, Foundations, Foundations&lt;/h3&gt;
&lt;p&gt;A common theme in instructor comments was that students need to learn the foundations and basic skills of the discipline before they can do much that's creative.  There's certainly some truth to this.  But how long of an apprenticeship can we expect somebody to serve before finally exposing them to the beauty and wonder, the &lt;i&gt;fun&lt;/i&gt; of the creative side?  Do we save up all the creative parts for a senior-level capstone course (or even later), or can we intersperse skill development with appropriately-scaled opportunities to use those skills creatively?&lt;/p&gt;
&lt;p&gt;A favorite movie of many teachers is &lt;a href="http://en.wikipedia.org/wiki/The_Karate_Kid"&gt;The Karate Kid&lt;/a&gt;, especially the part where Mr. Miyagi teaches Daniel karate by having him do household chores such as waxing cars or painting fences.  Eventually Daniel rebels at what he sees as pointless menial labor, and Mr. Miyagi demonstrates that Daniel has been learning valuable defensive moves all along.  The point teachers usually draw from this example is that students can learn valuable lessons without realizing that they are learning, but there's another point here as well.  What if, instead of confronting Mr. Miyagi, Daniel simply quit coming to his lessons?  That's the situation we face as college teachers.  If we give students too much skills development up front without any hint of a payoff, they'll simply stop taking our courses and never come back.&lt;/p&gt;
&lt;p&gt;There's another danger as well.  I saw this among my fellow students in graduate school.  Students who had spent their entire undergraduate careers very successfully learning foundations and practicing skills were often lost when they were finally expected to do creative research.  It was completely different from what they were used to, and often they found that they didn't like it.&lt;/p&gt;
&lt;p&gt;Think of a piano teacher who makes her students practice nothing but scales for four years.  By the time she feels her students are finally ready to play real music, she may find that the only students she has left are the ones who would rather play scales than anything else.&lt;/p&gt;
&lt;h3&gt;But...it's hard!&lt;/h3&gt;
&lt;p&gt;Incorporating creativity into a college classroom can be hard, especially in large classes.  The lecture format is particularly bad at nurturing creativity in the listeners, but a teacher facing several hundred students often has little choice.&lt;/p&gt;
&lt;p&gt;Grading also becomes substantially more difficult if you design assignments that allow students room for creativity.  Suddenly, there's no longer a single, &amp;ldquo;approved&amp;rdquo; solution that can be easily checked for.  Instead, you need judgement to evaluate quite different solutions individually.  This can be especially difficult in a course where TAs are expected to do most of the grading.&lt;/p&gt;
&lt;p&gt;Fortunately, I suppose, I don't have large class sizes and I don't have any TAs, so I don't have those excuses to fall back on.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7880837608298063768?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7880837608298063768/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7880837608298063768' title='4 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7880837608298063768'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7880837608298063768'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/05/barriers-to-creativity.html' title='Barriers to Creativity'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>4</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-7475461971466079068</id><published>2008-05-02T14:29:00.000-04:00</published><updated>2008-05-02T14:29:32.389-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Beware Pseudo-Arrays</title><content type='html'>&lt;p&gt;I'm always fascinated by the kinds of programming mistakes that novices make, and what they say about that student's state of mind.  I particularly enjoy mistakes that aren't really mistakes, in the sense that the student has actually gotten the code to work, but where the code clearly demostrates some flaw in that student's mental model of programming.  For example, see my previous post on &lt;a href="http://okasaki.blogspot.com/2008/02/boolean-confusion.html"&gt;Boolean confusion&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Here's another example involving arrays, or rather the lack of them.  I was reminded of this example just yesterday when multiple teams tried to use this idea in a local programming contest.&lt;/p&gt;
&lt;p&gt;Suppose you are rolling some standard six-sided dice, and keeping track of how many times each number has appeared.  The most natural way to do this would be to use an array indexed from 1-6.  In a language with zero-based arrays, you might use indices 0-5 and subtract 1 from each die value, or you might use indices 0-6 and simply ignore index 0.&lt;/p&gt;
&lt;p&gt;However, many novices faced with this decision will reject arrays altogether and use six separate variables, perhaps named &lt;tt&gt;count1&lt;/tt&gt;, &lt;tt&gt;count2&lt;/tt&gt;, &lt;tt&gt;count3&lt;/tt&gt;, &lt;tt&gt;count4&lt;/tt&gt;, &lt;tt&gt;count5&lt;/tt&gt;, and &lt;tt&gt;count6&lt;/tt&gt;.  (Or, if they are really gluttons for punishment, &lt;tt&gt;ones&lt;/tt&gt;, &lt;tt&gt;twos&lt;/tt&gt;, &lt;tt&gt;threes&lt;/tt&gt;, &lt;tt&gt;fours&lt;/tt&gt;, &lt;tt&gt;fives&lt;/tt&gt;, and &lt;tt&gt;sixes&lt;/tt&gt;.)  I call these kinds of variables &lt;i&gt;pseudo-arrays&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Why use pseudo-arrays?  Because real arrays are scary.  Plain variables and if-statements are much friendlier!  After all, why write
&lt;pre&gt;
   count[dieValue]++;
&lt;/pre&gt;
when you could write
&lt;pre&gt;
   if (dieValue == 1) {
      count1++;
   }
   else if (dieValue == 2) {
      count2++;
   }
   else if (dieValue == 3) {
      count3++;
   }
   else if (dieValue == 4) {
      count4++;
   }
   else if (dieValue == 5) {
      count5++;
   }
   else {
      count6++;
   }
&lt;/pre&gt;
Oh, and don't bother suggesting a switch-statement &amp;#8212; if-statements are good enough, thank you very much.&lt;/p&gt;
&lt;p&gt;Why do so many novices do this?  In many cases, I think it is because they were first exposed to if-statements, and found them easy, and then later were exposed to loops, and found them difficult.  Arrays are usually processed using loops, and are usually introduced while the beginner is still reeling from the trauma of loops.  Thus, arrays become tainted and suspect.  In such a novice's mind, the approach with variables and if-statements truly is easier, especially because so many of the if-statements can be programmed using cut-and-paste &amp;#8212; the favorite editing commands of most novice programmers!&lt;/p&gt;
&lt;p&gt;Every once in a while, I see code by somebody who has gotten over their fear of loops, but has not yet become reconciled with arrays.  This can lead to gems where the student tries to loop through a pseudo-array, as in
&lt;pre&gt;
   for (int d = 1; d &amp;lt;= 6; d++) {
      if (d == 1) {
         System.out.println(count1);
      }
      else if (d == 2) {
         System.out.println(count2);
      }
      else if (d == 3) {
         System.out.println(count3);
      }
      else if (d == 4) {
         System.out.println(count4);
      }
      else if (d == 5) {
         System.out.println(count5);
      }
      else {
         System.out.println(count6);
      }
   }
&lt;/pre&gt;
As Dave Barry would say, I am not making this up.
&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-7475461971466079068?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/7475461971466079068/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=7475461971466079068' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7475461971466079068'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/7475461971466079068'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/05/beware-pseudo-arrays.html' title='Beware Pseudo-Arrays'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-2342069181638891642</id><published>2008-04-17T08:41:00.000-04:00</published><updated>2008-04-17T08:42:16.701-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Games for Programmers: Jotto</title><content type='html'>&lt;p&gt;&lt;i&gt;The next in an irregular series of board game recommendations for programmers. Of course, you don't have to be a programmer to enjoy these games, but if you are a programmer, then I think there's a pretty good chance that you'll like them.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;However, you might not want to play this particular game with your spouse.  Here's why...&lt;/i&gt;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;End. E-N-D&amp;rdquo;, she guessed. &amp;ldquo;One&amp;rdquo;, I replied.&lt;br&gt;
&amp;ldquo;Cab. C-A-B&amp;rdquo;, I guessed. &amp;ldquo;One&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;We were driving to a campground in Massachusetts. My wife and I were in the front seats of the minivan; our daughter was in the middle seat, watching a DVD; and our son and his friend were chatting in the back seat.&lt;/p&gt;

&lt;p&gt;We had been on the road for several hours, and I was feeling a bit tired. I needed to do something to help keep me alert. &amp;ldquo;Jotto?&amp;rdquo;, I suggested to my wife. &amp;ldquo;Ok.&amp;ldquo;&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Icy. I-C-Y&amp;rdquo;, she guessed. &amp;ldquo;Zero&amp;rdquo;, I replied.&lt;br&gt;
&amp;ldquo;Fed. F-E-D&amp;rdquo;, I guessed. &amp;ldquo;One&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="http://www.boardgamegeek.com/game/11821"&gt;Jotto&lt;/a&gt; is a two-player deduction game, kind of like Mastermind but with words. In fairness, I should say that Mastermind is like Jotto but with colors, since Jotto is older than Mastermind.&lt;/p&gt;

&lt;p&gt;Each player secretly chooses a five-letter word with no duplicate letters. The usual restrictions apply&amp;#8212;no proper nouns, etc.&lt;/p&gt;

&lt;p&gt;The players take turns guessing each other's words. For each guess, you tell the player how many letters were correct. Unlike Mastermind, it doesn't matter whether the letter is in the right position or not. For example, if you guessed BOARD and got one letter right, the answer might be PLAYS (the A matches, in the same place) but it could just as easily be GAMES (the A matches, not in the right place).&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Map. M-A-P&amp;rdquo;, she guessed. &amp;ldquo;One&amp;rdquo;, I replied.&lt;br&gt;
&amp;ldquo;Jig. J-I-G&amp;rdquo;, I guessed. &amp;ldquo;Zero&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Jotto is a favorite game for situations where it would not be feasible to set up a board or deal out cards. For example, you can easily play it in a restaurant, or waiting in line, or on a long drive. All you need is two pencils and two pieces of paper.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Age. A-G-E&amp;rdquo;, she guessed. &amp;ldquo;Two&amp;rdquo;, I replied.&lt;br&gt;
&amp;ldquo;Out. O-U-T&amp;rdquo;, I guessed. &amp;ldquo;Zero&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;In fact, you don't even need the pencil and paper! Most of the time, we play it in our heads with three-letter words instead of five. This is a great variation that allows the driver to play in the car. It also lets you play in situations where you are moving too much to be able to take notes comfortably, such as jogging or hiking.&lt;/p&gt;
&lt;p&gt;For this game, I picked AXE as my word.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Axe. A-X-E&amp;rdquo;, she guessed. &amp;ldquo;Got it. Dang that was fast!&amp;rdquo;, I replied.&lt;br&gt;
&amp;ldquo;Men. M-E-N&amp;rdquo;, I guessed. &amp;ldquo;One&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;I started playing Jotto this way with my son when he was 10. We still enjoy it and play it often, but it has become kind of a running joke, because we almost always finish within one guess of each other. This is the first time I have played mental Jotto with my wife, and she's killing me! She got it in five guesses, and I'm not even close!&lt;/p&gt;

&lt;p&gt;Ok, with ones for both FED and MEN, I guess that it probably has an E. Next, I want to figure out which letter from CAB was correct. I'll try the A, and I'll also throw one of the other letters from FED to help confirm that it really was the E.&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Far. F-A-R&amp;rdquo;, I guessed. &amp;ldquo;One&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Good. It probably really was the A. What has an E and an A?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Sea. S-E-A&amp;rdquo;, I guessed. &amp;ldquo;Two&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Now I'm getting somewhere. It looks like the E-A is correct. What else has an E-A?&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Pea. P-E-A&amp;rdquo;, I guessed. &amp;ldquo;Two&amp;rdquo;, she replied.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Hmm. I'm nearly certain now that the E-A are correct. What else has an E-A? It can't be TEA because I already got a zero for OUT. What if it's A-E instead of E-A?&lt;/p&gt;

&lt;p&gt;Wait a minute. No way. No, she couldn't possibly have picked...&lt;/p&gt;

&lt;p&gt;&lt;b&gt;&amp;ldquo;Axe. A-X-E&amp;rdquo;, I guessed. &amp;ldquo;Got it&amp;rdquo;, she laughed.&lt;/b&gt;&lt;/p&gt;

&lt;p&gt;Oh, man. We really have been married too long.&lt;/p&gt;

&lt;p&gt;&lt;i&gt;Originally written as a session report for &lt;a href="http://www.boardgamegeek.com/"&gt;BoardGameGeek&lt;/a&gt;.&lt;/i&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-2342069181638891642?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/2342069181638891642/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=2342069181638891642' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2342069181638891642'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2342069181638891642'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/04/games-for-programmers-jotto.html' title='Games for Programmers: Jotto'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-8844182676029449734</id><published>2008-04-14T10:50:00.000-04:00</published><updated>2008-04-14T10:54:41.769-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='creativity'/><title type='text'>Creativity</title><content type='html'>&lt;p&gt;I recently stumbled across &lt;a href="http://www.ted.com/index.php/talks/view/id/66"&gt;the TED video by Ken Robinson&lt;/a&gt; (via &lt;a href="http://gametheorist.blogspot.com/2008/03/its-funny-cause-its-true.html"&gt;Joshua Gans&lt;/a&gt;).  This video is almost two years old, so I'm getting to it rather late.&lt;/p&gt;&lt;p&gt;Robinson describes the increasing importance of creativity in the modern world, and bashes the education system for &amp;ldquo;educating people out of their creativity&amp;rdquo;.  He contends that &amp;ldquo;creativity now is as important in education as literacy and we should treat it with the same status&amp;rdquo;.  Robinson is an entertaining speaker, and I quite enjoyed his video.  However, as I thought about it later, I become more dissatisfied.&lt;/p&gt;&lt;p&gt;I agree that creativity is important, and that the education system is doing a terrible job nurturing creativity.  My problem with his talk is that he equates creativity with the arts: drawing, drama, dance, etc.  I would hate to see some school administrator be inspired by the talk and attempt to &amp;ldquo;solve&amp;rdquo; the problem by simply adding an extra art class to the curriculum.&lt;/p&gt;&lt;p&gt;I'm not anti-arts.  I'm not saying that art classes are bad.  I am saying that giving students one art class in which to be creative, while systematically sucking the creativity out of them in every other class, is not going to solve the problem.&lt;/p&gt;&lt;p&gt;Instead, we need to recognize that other disciplines outside the arts also require creativity, and teach them that way.  For example, mathematics is often taught in a way that brooks no creativity whatsoever, whereas the practice of actually doing real mathematics is highly creative.  See &lt;a href="http://www.maa.org/devlin/devlin_03_08.html"&gt;Paul Lockhart's essay&lt;/a&gt; (&lt;a href="http://www.maa.org/devlin/LockhartsLament.pdf"&gt;pdf&lt;/a&gt;) for a wonderful discussion about creativity in mathematics education.&lt;/p&gt;&lt;p&gt;I think people often view technical subjects as having no place for creativity.  You don't want a student getting creative when multiplying two numbers.  I certainly don't want my programming students getting creative about &lt;a href="http://okasaki.blogspot.com/2008/02/in-praise-of-mandatory-indentation-for.html"&gt;indentation&lt;/a&gt;.  In fact, in many technical subjects, the very word &lt;i&gt;creative&lt;/i&gt; is often used as a synonym for &lt;i&gt;wrong&lt;/i&gt; or &lt;i&gt;mistaken&lt;/i&gt; (or sometimes &lt;i&gt;unethical&lt;/i&gt;, as in &amp;ldquo;creative accounting&amp;rdquo;).&lt;/p&gt;&lt;p&gt;For example, I just said that you don't want a student getting creative when multiplying two numbers.  But that's only because, in that context, &amp;ldquo;getting creative&amp;rdquo; would usually be interpreted as getting the wrong answer.  In reality, I'd be thrilled if my grade-schooler, when faced with a multiplication problem like 37x999, rejected &lt;a href="http://www.mathsisfun.com/numbers/multiplication-long.html"&gt;long multiplication&lt;/a&gt; and instead said, &amp;ldquo;Hmm.  999 is almost 1000.  37x1000 is 37000.  Then take away 37 to get 36963.&amp;rdquo;  That's creativity!&lt;/p&gt;&lt;p&gt;Perhaps the biggest difference between creativity in the arts and in technical subjects has to do with constraints.  In the arts, you tend to have fewer constraints, and those constraints are often flexible.  In technical subjects, you tend to have more constraints, and those constraints are often non-negotiable.  Think of the scene from &lt;a href="http://www.imdb.com/title/tt0112384/"&gt;Apollo 13&lt;/a&gt;: &amp;ldquo;We've got to find a way to make this...fit into the hole for this...using nothing but that.&amp;rdquo;  Or the t-shirt about the speed of light that says &amp;ldquo;300,000 kilometers per second: It's not just a good idea, IT'S THE LAW!&amp;rdquo;&lt;/p&gt;&lt;p&gt;Common perception is that, the more constraints you have, the less creativity is involved.  I don't think that's true.  In fact, as Marissa Mayer of Google fame says, &lt;a href="http://edcorner.stanford.edu/authorMaterialInfo.html?mid=1530&amp;author=205"&gt;creativity loves constraints&lt;/a&gt;.  Of course, sometimes the creativity lies in figuring out which constraints are real, and which aren't.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-8844182676029449734?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/8844182676029449734/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=8844182676029449734' title='9 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8844182676029449734'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8844182676029449734'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/creativity.html' title='Creativity'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>9</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-2186132957097733411</id><published>2008-04-08T23:33:00.001-04:00</published><updated>2008-04-08T23:36:04.889-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='failure'/><title type='text'>Immortality</title><content type='html'>&lt;p&gt;Last week, I wrote about one of my more &lt;a href="http://okasaki.blogspot.com/2008/04/spectacular-failure.html"&gt;spectacular failures&lt;/a&gt;, which involved a progression that began 1, 2, 4, 8, 16, 32, but then rather than continuing sensibly as 64, 128, ..., instead exploded into 273, 65569, 4294967361, and 1.5x10&lt;sup&gt;82&lt;/sup&gt;.  The next term is a little over 2&lt;sup&gt;65569&lt;/sup&gt; and the term after that a little over 2&lt;sup&gt;4294967361&lt;/sup&gt;, which has about a &lt;i&gt;billion&lt;/i&gt; digits when written out in full.&lt;/p&gt;
&lt;p&gt;Joshua Zucker suggested that I submit this to the &lt;a href="http://www.research.att.com/~njas/sequences/Seis.html"&gt;On-Line Encyclopedia of Integer Sequences&lt;/a&gt;, which I did.  So I've now been immortalized in Sequence &lt;a href="http://www.research.att.com/~njas/sequences/A137181"&gt;A137181&lt;/a&gt;.  I can see my tombstone now: &amp;ldquo;He failed...BIG.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Several years ago I was giving a guest lecture in a colleague's Algorithms class, when I encountered immortality of a different sort.  The students were asking me about how I invented &amp;ldquo;Okasaki trees&amp;rdquo;, and were dumbfounded when I didn't know what they were talking about.  How could I not know about Okasaki trees when I invented them?  &amp;ldquo;Well,&amp;rdquo; I told them, &amp;ldquo;I've invented a lot of different &lt;a href="http://okasaki.blogspot.com/2008/02/ten-years-of-purely-functional-data.html"&gt;data structures&lt;/a&gt;, and most of them are trees of one kind or another.  But I've never called any of them Okasaki trees.&amp;rdquo;  After a bit more digging, it turned out that my colleague (who wasn't there that day) had been telling them the previous week about my simplification of red-black trees, and &lt;i&gt;he&lt;/i&gt; called them Okasaki trees.&lt;/p&gt;
&lt;p&gt;The lasting result of this is that I now have a friend at work who ribs me about Okasaki trees every chance she gets.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-2186132957097733411?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/2186132957097733411/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=2186132957097733411' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2186132957097733411'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2186132957097733411'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/04/immortality.html' title='Immortality'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-4225500553816081483</id><published>2008-04-04T00:18:00.001-04:00</published><updated>2008-04-04T08:02:02.770-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='failure'/><title type='text'>A Spectacular Failure</title><content type='html'>&lt;p&gt;About five years ago, a mathematical puzzle occurred to me.  I eventually solved the puzzle, but I don't want to talk about that solution here.  Instead, I want to talk about my &lt;i&gt;first&lt;/i&gt; attempt at solving the puzzle, which was an utter failure.  A glorious, spectacular failure.  Perhaps the single most impressive failure of my career.  Failures are often much more interesting than successes, but for some unfathomable reason, people are often reluctant to discuss them.&lt;/p&gt;
&lt;h3&gt;The Puzzle and My &amp;ldquo;Solution&amp;rdquo;&lt;/h3&gt;
&lt;p&gt;&lt;i&gt;You don't need to understand the details of the puzzle to enjoy the failure, so if you're not familiar with &lt;a href="http://en.wikipedia.org/wiki/SKI_combinator_calculus"&gt;SK combinators&lt;/a&gt; and their ilk, or if you just can't be bothered, then please skip ahead to the &lt;a href="#nextSection"&gt;next section.&lt;/a&gt;&lt;/i&gt;&lt;/p&gt;&lt;p&gt;I was playing around with SK combinators one day when a puzzle occurred to me.  Could I introduce new combinators that would allow me to linearize any combinator expression?  Combinator expressions are normally binary trees, and are written using parentheses to indicate the tree structure.  The convention is that parentheses on the left can be omitted.  For example, ((&lt;i&gt;w&lt;/i&gt; &lt;i&gt;x&lt;/i&gt;) &lt;i&gt;y&lt;/i&gt;) &lt;i&gt;z&lt;/i&gt; can be written as &lt;i&gt;w x y z&lt;/i&gt;, but &lt;i&gt;w&lt;/i&gt; (&lt;i&gt;x&lt;/i&gt; (&lt;i&gt;y&lt;/i&gt; &lt;i&gt;z&lt;/i&gt;)) cannot be written without parentheses.  I wondered if I could introduce new combinators that would allow me to rewrite any expression into an equivalent expression with no parentheses.  I called such a transformation &amp;ldquo;flattening&amp;rdquo;.&lt;/p&gt;&lt;p&gt;One of the standard combinators in the SK family is B, which has the rewrite rule&lt;center&gt;B &lt;i&gt;f&lt;/i&gt; &lt;i&gt;g&lt;/i&gt; &lt;i&gt;x&lt;/i&gt; = &lt;i&gt;f&lt;/i&gt; (&lt;i&gt;g&lt;/i&gt; &lt;i&gt;x&lt;/i&gt;)&lt;/center&gt;Reading this rule backwards works well for flattening small expressions&amp;#8212;for example, &lt;i&gt;x&lt;/i&gt; (&lt;i&gt;y&lt;/i&gt; &lt;i&gt;z&lt;/i&gt;) can be rewritten without parentheses as B &lt;i&gt;x&lt;/i&gt; &lt;i&gt;y&lt;/i&gt; &lt;i&gt;z&lt;/i&gt;&amp;#8212;but I ran into problems using it to flatten larger expressions, so I quickly turned to a variation of B that swaps the first two arguments
&lt;center&gt;R &lt;i&gt;f&lt;/i&gt; &lt;i&gt;g&lt;/i&gt; &lt;i&gt;x&lt;/i&gt; = &lt;i&gt;g&lt;/i&gt; (&lt;i&gt;f&lt;/i&gt; &lt;i&gt;x&lt;/i&gt;)&lt;/center&gt;  This new combinator works well for flattening expressions of the form &lt;i&gt;c&lt;/i&gt; (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; ... &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;N&lt;/sub&gt;).  For example,&lt;pre&gt;   &lt;i&gt;c&lt;/i&gt; (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; ... &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;7&lt;/sub&gt;)
       = R (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; ... &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;6&lt;/sub&gt;) &lt;i&gt;c&lt;/i&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;7&lt;/sub&gt;
       = R (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; ... &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;5&lt;/sub&gt;) R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;6&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;7&lt;/sub&gt;
       = R (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; ... &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;4&lt;/sub&gt;) R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;5&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;6&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;7&lt;/sub&gt;
       ...
       = R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;4&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;5&lt;/sub&gt; R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;6&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;7&lt;/sub&gt;
&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;Now, another combinator F works in conjunction with R to flatten more complicated expressions.  F is defined as&lt;center&gt;F &lt;i&gt;f&lt;/i&gt; &lt;i&gt;g&lt;/i&gt; &lt;i&gt;x&lt;/i&gt; &lt;i&gt;y&lt;/i&gt; = &lt;i&gt;f&lt;/i&gt; &lt;i&gt;x&lt;/i&gt; (&lt;i&gt;g&lt;/i&gt; &lt;i&gt;y&lt;/i&gt;)&lt;/center&gt; For example, we can now rewrite &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; (&lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;)
 as follows:&lt;pre&gt;   &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; (&lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;)
      = F (&lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt;) (&lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt;) &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;
      = R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; F &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; (&lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt;) &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;
      = F (R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; F) &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;
      = R (R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt;) F F &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;
      = R R R &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; F F &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;1&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;2&lt;/sub&gt; &lt;i&gt;c&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt; &lt;i&gt;d&lt;/i&gt;&lt;sub&gt;3&lt;/sub&gt;
&lt;/pre&gt;&lt;/p&gt;&lt;p&gt;The complete rules for flattening are
&lt;ul&gt;
&lt;li&gt; flatten(&lt;i&gt;c&lt;/i&gt;) = &lt;i&gt;c&lt;/i&gt; &lt;/li&gt;
&lt;li&gt; flatten(&lt;i&gt;e&lt;/i&gt; &lt;i&gt;c&lt;/i&gt;) = flatten(&lt;i&gt;e&lt;/i&gt;) &lt;i&gt;c&lt;/i&gt; &lt;/li&gt;
&lt;li&gt; flatten(&lt;i&gt;c1&lt;/i&gt; (&lt;i&gt;e&lt;/i&gt; &lt;i&gt;c2&lt;/i&gt;)) = flatten(R &lt;i&gt;e&lt;/i&gt; &lt;i&gt;c1&lt;/i&gt; &lt;i&gt;c2&lt;/i&gt;) &lt;/li&gt;
&lt;li&gt; flatten(&lt;i&gt;e1&lt;/i&gt; &lt;i&gt;c1&lt;/i&gt; (&lt;i&gt;e2&lt;/i&gt; &lt;i&gt;c2&lt;/i&gt;)) = flatten(F &lt;i&gt;e1&lt;/i&gt; &lt;i&gt;e2&lt;/i&gt; &lt;i&gt;c1&lt;/i&gt; &lt;i&gt;c2&lt;/i&gt;) &lt;/li&gt;
&lt;li&gt; flatten(&lt;i&gt;e1&lt;/i&gt; &lt;i&gt;e2&lt;/i&gt;) = flatten(flatten(&lt;i&gt;e1&lt;/i&gt;) flatten(&lt;i&gt;e2&lt;/i&gt;)) &lt;/li&gt;
&lt;/ul&gt;
where each &lt;i&gt;c&lt;/i&gt; is a simple symbol and each &lt;i&gt;e&lt;/i&gt; is an arbitrary expression.&lt;/p&gt;
&lt;h3&gt;&lt;a name="nextSection"&gt;&lt;/a&gt;Not So Fast&lt;/h3&gt;
&lt;p&gt;I run my solution by hand on a few examples and it works great.  So I code it up, run it on my examples and get the same answers.  Yippee!  Next, I run it on a larger example and.........nothing.  The computer justs sits there, mocking me.  Obviously, I've got a bug somewhere that is causing infinite recursion.&lt;/p&gt;&lt;p&gt;I stare at my program for awhile, but I'm not seeing any bugs.  Hmmm.  I run it on a different example and it finishes this time.  I print out the result and...whoa, that's a lot of output!  I wonder how big the transformed expressions are?  Ok, calculating the size of the result shouldn't be too hard.  I whip up another program and print out a table of the maximum output for an input of size N.
&lt;pre&gt;   N=1     max output=1
     2                2
     3                4
     4                8
     5                16
     6                32
     .
     .
     .
     .
&lt;/pre&gt;
Quick!  Guess the next value in the table!  64, right?  RIGHT?!
&lt;pre&gt;
     .
     .
     .
     .
     .
     7                273
     .
     .
     .
     .
     .
&lt;/pre&gt;
Huh?  273?  What the heck is that?
&lt;pre&gt;
     .
     .
     .
     .
     .
     8                65,569
     .
     .
     .
     .
     .
&lt;/pre&gt;
65,569?! You're joking, right?
&lt;pre&gt;
     .
     .
     .
     .
     .
     9                4,294,967,361
     .
     .
     .
     .
     .
&lt;/pre&gt;
4 billion?  Well, that's just silly.
&lt;pre&gt;     .
     .
     .
     .
     .
     10      15,177,100,720,513,508,366,
            558,296,147,058,741,458,143,
            803,430,094,840,009,779,784,
            451,085,189,728,165,691,939&lt;/pre&gt;
&lt;p&gt;
What do you even say to a number like that?  That's 1.5x10&lt;sup&gt;82&lt;/sup&gt;.  To put that in perspective, &lt;a href="http://en.wikipedia.org/wiki/Observable_universe#Matter_content"&gt;the number of atoms in the observable universe&lt;/a&gt; is estimated to be about 10&lt;sup&gt;80&lt;/sup&gt;.  No wonder my program was running slow!  At a few billion operations a second, that calculation should only take about...um...carry the 3...dang, where's &lt;a href="http://www.ted.com/index.php/talks/view/id/199"&gt;Art Benjamin&lt;/a&gt; when you need him?...let's just say &lt;i&gt;a long time&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;If you're curious, here's the function that describes the size of the biggest possible output for an input of size N:
&lt;ul&gt;
&lt;li&gt;Biggest(N) = 2^(N-1), if N &amp;lt;= 6&lt;/li&gt;
&lt;li&gt;Biggest(N) = 2^Biggest(N-3) + 2*Biggest(N-3) + 1, if N &amp;gt; 6&lt;/li&gt;
&lt;/ul&gt;
And here's the input of size 10 that gives the absurd result above:&lt;center&gt;X (X X) (X (X X) (X (X (X X))))&lt;/center&gt;
&lt;/p&gt;&lt;p&gt;Once I recovered from the shock of this experience, I did eventually come up with a very nice solution to the puzzle, based on ideas from postfix languages like Forth and Postscript, but nothing quite compares with getting an answer like 1.5x10&lt;sup&gt;82&lt;/sup&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-4225500553816081483?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/4225500553816081483/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=4225500553816081483' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4225500553816081483'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4225500553816081483'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/04/spectacular-failure.html' title='A Spectacular Failure'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-2123090977581497109</id><published>2008-03-28T12:15:00.001-04:00</published><updated>2008-03-28T12:16:11.064-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='rant'/><category scheme='http://www.blogger.com/atom/ns#' term='computational thinking'/><title type='text'>Wrong Number</title><content type='html'>&lt;p&gt;Is it time to overhaul the user interface of the phone system?&lt;/p&gt;
&lt;p&gt;A few months ago we started getting a lot of calls that were wrong numbers.  Before that we used to get maybe one a week, but suddenly we were getting 5 or 6 a day.  After an initial period of frustration, we eventually started to apply our debugging skills.&lt;/p&gt;
&lt;p&gt;Our first guess was that somebody was distributing our phone number on a flyer or something, either as a prank or by accident.  But this didn't make sense because every caller was asking for somebody different.  &amp;ldquo;Hello, is Juan there?&amp;rdquo; &amp;ldquo;Hi, Elizabeth/Gary/Tanya/Carlos?&amp;rdquo; Or the ever popular &amp;ldquo;&amp;lt;&lt;i&gt;pause&lt;/i&gt;&amp;gt; Who is this?!!&amp;rdquo; No, dude, you called me, so you tell first.&lt;/p&gt;
&lt;p&gt;Ok, scratch that idea. Hmm, I suppose we could always ask.  &amp;ldquo;Sorry, wrong number, what number are you trying to reach?&amp;rdquo;  At last, some progress. Our phone number is 987-654-3210 (not our real number).  The people who were calling us were uniformly dialing 654-321-0xxx.  The 654 area code is for an area maybe 20 miles away, so &lt;i&gt;lots&lt;/i&gt; of people in our area code were dialing numbers there.  Even worse, there are up to 1000 numbers in that area code that match this pattern.  No wonder we were getting a lot of calls!&lt;/p&gt;
&lt;p&gt;The reason they were getting us was that they were forgetting to dial a 1 first.  Without the 1, the phone system was interpreting this as a local call within the 987 area code to 654-3210, with the extra three digits on the end simply being ignored.  On many (most?) cell phones the 1 is not necessary, so people lose the habit of dialing it.  Then when they use a land line, where the 1 is required, they get us.&lt;/p&gt;
&lt;p&gt;With this insight, we contacted the phone company.  It took three tries and many patient explanations to even get somebody to understand what the problem was.  I asked what had changed in the system recently, because clearly something had changed to cause the sudden increase in wrong numbers.&lt;/p&gt;  &amp;ldquo;Uh, I don't know.  I'll ask our tech guy.&amp;rdquo;  A few minutes later.  &amp;ldquo;Our tech guy says the 321 exchange in the 654 area code is a Cingular exchange.  You should call them.&amp;rdquo;  &amp;ldquo;But how is that supposed to help?  The phone calls are originating in your system and never getting out of your system, so even if they made a change over there, it wouldn't change what's happening here.&amp;rdquo;  &amp;ldquo;Well, you should call Cingular.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Predictably, Cingular couldn't help.  They couldn't even tell us if the 321 exchange was new because &amp;ldquo;our computers don't tell us that&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The really frustrating thing about the problem is that it's so easy to fix.  It should be easy for the system to detect when somebody has dialed a 10 digits but is being connected to a 7-digit number.  Give the caller a warning and ask them to redial!  It's possible this might break some systems with extensions, where the leftover 3 digits indicate the extension.  So perhaps disable the warning if there is a pause between the 7th and 8th digits.&lt;/p&gt;
&lt;p&gt;Has anyone else had this problem?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-2123090977581497109?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/2123090977581497109/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=2123090977581497109' title='5 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2123090977581497109'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/2123090977581497109'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/wrong-number.html' title='Wrong Number'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>5</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-1113463586386734001</id><published>2008-03-19T15:29:00.001-04:00</published><updated>2008-03-19T15:34:10.566-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Program Testing For The Sake Of Learning</title><content type='html'>&lt;p&gt;A number of years ago, I used to compete in the &lt;a href="http://www.topcoder.com/tc"&gt;TopCoder&lt;/a&gt; on-line programming contests. As an educator, I was fascinated by the TopCoder environment, less by the contests themselves than by the so-called &lt;i&gt;Practice Rooms&lt;/i&gt;. These were archives of problems from old contests, where you could submit solutions and run them against the test data used in the actual contest.&lt;/p&gt;&lt;p&gt;I was amazed by how hard many people would work in the Practice Rooms. I wished I could get my students to work half that hard! At first, I thought these people were motivated by the idea of doing better in the contest. And, indeed, that was probably what got most of them to come to the Practice Rooms in the first place. But then I noticed that many of the people working hard in the Practice Rooms competed only rarely, if at all. Something else was going on.&lt;/p&gt;&lt;p&gt;Eventually, it dawned on me that the secret lay in the ease of running system tests.  As teachers, we know that feedback is crucial to learning, and that quick feedback is better than slow feedback.  These programmers were getting feedback within a few seconds, while they were still &amp;ldquo;in the moment&amp;rdquo;.  The experience of this tight, nearly instantaneous feedback loop was so powerful that it kept them coming back for more.  The burning question then was &lt;i&gt;could I re-create this experience in the classroom?&lt;/i&gt;&lt;/p&gt;&lt;h3&gt;Why test?&lt;/h3&gt;&lt;p&gt;Of course, program testing has been part of CS education forever.  However, there are several different reasons for testing, and which reason or reasons the teacher has in mind will strongly affect how testing plays out in any particular class.&lt;/p&gt;&lt;p&gt;Here are several common reasons for testing:&lt;/p&gt;&lt;p&gt;&lt;b&gt;Improved software quality.&lt;/b&gt; Ironically, the number one reason for using testing in the real world is the least important reason to use it in the classroom.  Most student programs, especially in early courses, will never be used for real.  What matters in these programs is not that students complete the program correctly, but &lt;a href="http://okasaki.blogspot.com/2008/03/get-job-done-but-what-is-job.html"&gt;what they learn&lt;/a&gt; in the process.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Easier grading.&lt;/b&gt;  Grading programs can be hard, especially if you have a lot of students.  Naturally, many CS educators seek to automate this process as much as possible.  Many systems exist that will run student programs against a set of instructor tests and record the results.  These results may used as a guide for human grading, or the results may entirely determine the student grade.  When testing is performed as part of the grading process, it is common for the actual test cases to be hidden from the students.&lt;/p&gt;&lt;p&gt;&lt;b&gt;To learn about testing.&lt;/b&gt; Of course, testing is a vital part of real-world software development.  Therefore, it is important to expose students to the testing process so they have some idea of how to do it.  However, care must be taken here, especially in early courses.  Hand-crafting good test cases is hard work.  If students are forced to fight through a heavy-weight testing process on toy problems, including making up their own tests, the lesson they frequently take away is that testing is much more trouble than it's worth.&lt;/p&gt;&lt;p&gt;&lt;b&gt;Testing as design.&lt;/b&gt; In recent years, &lt;i&gt;test-first&lt;/i&gt; and &lt;i&gt;test-driven&lt;/i&gt; development have begun to spread from agile programming into the classroom.  Advocates view such testing as part of the design process.  By writing tests before writing code, students are forced to consider what the behavior of the program should be, rather than diving in without a clear idea of what the program is supposed to do.&lt;/p&gt;&lt;h3&gt;Another way&lt;/h3&gt;&lt;p&gt;All of these reasons are important, but none of them quite capture what I was seeing in the TopCoder practice rooms.  There, people were becoming addicted to quick, easy-to-run tests as a powerful learning experience.  This suggests viewing program testing as a way to improve learning.  Not learning about testing, but learning about the content being tested.&lt;/p&gt;&lt;p&gt;In an attempt to re-create the relevant parts of the TopCoder experience in the classroom, I adopted the following process.  With most programming assignments, I distribute some testing code and test cases.  Students then run these tests while they are developing their programs, and they turn in their test results along with their code.&lt;/p&gt;&lt;p&gt;Note that this is an extremely lightweight process.  All I'm doing is adding maybe 20 lines of test-driver code to the code I distribute for each assignment, and I can usually cut-and-paste that code from the previous assignment, with only a few tweaks.  I then add maybe 50-100 test cases, either hardwired into the code or in a separate text file.  I usually generate perhaps 5 of the tests by hand, and the rest randomly.  Usually this process adds about 20-30 minutes to the time it takes me to develop an assignment.&lt;/p&gt;&lt;p&gt;I think CS teachers are often scared away by ideas like this because they imagine a fancy system with a server where students submit their programs, and the server runs the tests and records the results into a database.  That all sounds like a lot of work, so teachers put it off until &amp;ldquo;next year&amp;rdquo;.  In contrast, what I'm suggesting could probably be added without much hassle to an assignment that is going out &lt;i&gt;tomorrow&lt;/i&gt;.&lt;/p&gt;&lt;p&gt;Similarly, teachers are sometimes scared away by the need to come up with the test suite, thinking it will take too much time to come up with a set of high-quality tests.  But that's not what I'm doing.  Experience has shown that large numbers of random tests work essentially as well as smaller numbers of hand-crafted tests, but at a fraction of the cost.  (See, for example, the wonderful &lt;a href="http://www.cs.chalmers.se/~rjmh/QuickCheck/"&gt;QuickCheck&lt;/a&gt; testing tool.)  Besides, I'm not trying to guarantee that my test suite will catch all possible bugs, which is a hopeless task anyway.  Instead, I'm providing a low-cost test suite that is good enough to gain most of the benefits I'm looking for.&lt;/p&gt;&lt;h3&gt;Benefits&lt;/h3&gt;&lt;p&gt;And just what are those benefits?  Well, since I started using this kind of testing in my homeworks, the general quality of submissions has gone up substantially.  Partly, this is because of a drastic decrease in the number of submissions that are complete nonsense.  When I did not require tests, students would write code that seemed correct to them at the time, and turn it in without testing it.  Now, they can still turn in complete nonsense, but at least they'll know that they are doing so.  Usually, however, when they see that they're failing every test, they'll go back and at least try to fix their code.  In addition, many students who would have gotten the problem almost right without testing now get it completely right with testing.&lt;/p&gt;&lt;p&gt;Which leads me to the second benefit&amp;#8212;there has been a noticeable improvement in the students' debugging skills.  As one student put it, &amp;ldquo;&lt;i&gt;[The testers] also taught us how to troubleshoot our problems. Without those test cases, many of us would have turned in products that were not even close to complete. This would have meant for worse grades and harder grading for the instructor. We also would not have been able to use and develop our troubleshooting skills. When we don't know that something is wrong, it is very hard to try to test for the failures.&lt;/i&gt;&amp;rdquo;&lt;/p&gt;&lt;p&gt;However, the main benefit is that the students are learning more.  They are getting needed feedback while they are still &amp;ldquo;in the moment&amp;rdquo;, and can immediately apply that feedback, which is all great for learning.  Contrast this, for example, to feedback that is received after an assignment has been turned in.  Often such feedback comes days or weeks later.  Students often don't even look at such feedback, but even if they do, they have often lost the context that would allow them to incorporate the feedback into their learning.  Even with an automated system that gives feedback instantly, if students do not have an opportunity to resubmit, then they will usually not bother to apply the feedback, and so will miss out on a substantial portion of the benefit to their learning.&lt;/p&gt;&lt;p&gt;As another student put it, &amp;ldquo;&lt;i&gt;The automated testers are much more than just a means of checking the block to ensure the program works. They function almost as an instructor themselves, correcting the student when he or she makes a mistake, and reaffirming the student's success when he or she succeeds. Late at night, several hours before the assignment is due, this pseudo-instructor is a welcome substitute.&lt;/i&gt;&amp;rdquo;&lt;/p&gt;&lt;h3&gt;Grading&lt;/h3&gt;&lt;p&gt;I have the students turn in the results of their testing, which makes grading significantly easier.  Failed tests give me clues about where to look in their programs, while passed tests tell me that I can focus more on issues such as style or efficiency than on correctness.&lt;/p&gt;&lt;p&gt;But this is merely a fringe benefit.  Note that I only use the test results to help guide my grading, not to determine grades automatically.  I worry that when grading becomes the primary goal of testing, it can interfere with the learning that is my primary goal.  For example, testing when used for grading often breaks the tight feedback loop that is where my students learn the most.&lt;/p&gt;&lt;p&gt;Also, when testing is used for grading, the instructor's test suite is often kept hidden from the students.  In contrast, I can make my test suites public, which saves me all kinds of headaches.  I'm not worried that a student might hardcode all the test cases into their code just to pass all the tests, because I'll see that when I look at their code.  (In fact, this happens about once a year.)  Students like having the test cases public because, if they don't understand something in the problem statement, they can often answer their own questions by looking at the test cases.&lt;/p&gt;&lt;p&gt;Admittedly, sometimes students take this too far.  I occasionally catch them poring over the test cases like trying to read tea leaves, instead of coming to ask me a 30-second question.&lt;/p&gt;&lt;h3&gt;Crawl-Walk-Run&lt;/h3&gt;&lt;p&gt;I am not advocating that this approach to testing should be used everywhere in the curriculum.  Among other things,  I agree that students should have the experience of creating their own test cases.  The question is when.&lt;/p&gt;&lt;p&gt;I see my approach as being most useful in beginning programming courses, and in courses that are not nominally about programming.  For example, it works particularly well in Algorithms.&lt;/p&gt;&lt;p&gt;In other programming courses, however, I believe that a crawl-walk-run approach is appropriate.  The &amp;ldquo;crawl&amp;rdquo; step is about attitude rather than skills; it is to convince students that testing is valuable.  I believe my approach does this, especially if you occasionally leave out the tests and explicitly ask students to compare the experiences of developing with or without tests.&lt;/p&gt;&lt;p&gt;The &amp;ldquo;walk&amp;rdquo; step might be to have students generate their own tests, but using instructor-supplied scaffolding.  The &amp;ldquo;run&amp;rdquo; step might be to have students generate both the tests and the scaffolding.  I admit, however, that I have not taught the courses in which those steps would be most appopriate.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-1113463586386734001?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/1113463586386734001/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=1113463586386734001' title='8 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1113463586386734001'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1113463586386734001'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/program-testing-for-sake-of-learning.html' title='Program Testing For The Sake Of Learning'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>8</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-4969461440807974839</id><published>2008-03-11T09:37:00.000-04:00</published><updated>2008-03-11T09:38:07.818-04:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Games for Programmers: Schotten Totten/Battle Line</title><content type='html'>&lt;p&gt;&lt;i&gt;The next in an irregular series of board game (or, in this case, card game) recommendations for programmers. Of course, you don't have to be a programmer to enjoy these games, but if you are a programmer, then I think there's a pretty good chance that you'll like them.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;In programming, the specifications you thought you were implementing are practically guaranteed to change by the time you're done.  Unless you have the power to &amp;ldquo;just say no&amp;rdquo; to the changes, the best approach is often to stay flexible by delaying commitments for as long as possible.  You try to keep your options open by putting off irreversible decisions to the last possble moment.  &lt;a href="http://www.boardgamegeek.com/game/372"&gt;Schotten Totten&lt;/a&gt; (by noted game designer &lt;a href="http://en.wikipedia.org/wiki/Reiner_Knizia"&gt;Reiner Knizia&lt;/a&gt;) elegantly captures this feeling in a short, two-player card game.&lt;/p&gt;
&lt;a href="http://3.bp.blogspot.com/_HOXl0OgNHo0/R82L4skNSMI/AAAAAAAAAAc/mBHoCiI8fRU/s1600-h/schottenbox.jpg"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;" src="http://3.bp.blogspot.com/_HOXl0OgNHo0/R82L4skNSMI/AAAAAAAAAAc/mBHoCiI8fRU/s320/schottenbox.jpg" border="0" alt="box cover" id="BLOGGER_PHOTO_ID_5173945353070528706" /&gt;&lt;/a&gt;&lt;p&gt;Schotten Totten is nominally about two Scottish clans squabbling over territory.  Nine boundary stones are placed between you and your opponent, in a line from left to right.  You win by being the first to claim either three adjacent stones or five stones altogether.  To claim a stone, you must play a better three-card group on your side of the stone than your opponent does.&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://2.bp.blogspot.com/_HOXl0OgNHo0/R82NmckNSNI/AAAAAAAAAAk/F4LFpMZWY-A/s1600-h/schottengame.jpg"&gt;&lt;img style="display:block; margin:0px; text-align:center;cursor:pointer; cursor:hand;" src="http://2.bp.blogspot.com/_HOXl0OgNHo0/R82NmckNSNI/AAAAAAAAAAk/F4LFpMZWY-A/s320/schottengame.jpg" border="0" alt="game in progress" id="BLOGGER_PHOTO_ID_5173947238561171666" /&gt;&lt;/a&gt;&lt;br&gt;(photo by &lt;a href="http://www.boardgamegeek.com/user/Aldie"&gt;Scott Alden&lt;/a&gt;)&lt;/p&gt;&lt;p&gt;There are a total of 54 cards, numbered 1-9 in six different colors.  Three-card groups are ranked as follows, from best to worst: straight flush (three consecutive numbers of the same color), three-of-a-kind (three of the same number), flush (three of the same color), straight (three consecutive numbers), &amp;ldquo;wild rabble&amp;rdquo; (anything else).  If both players play the same kind of group, then each player adds their cards together and the player with the higher sum wins.  If there is still a tie, the player who completed their group first wins.&lt;/p&gt;&lt;p&gt;You start the game with six cards.  Each turn you play a single card on your side of one of the stones, and then draw a replacement card.  (For beginners, the play-then-draw order can be a little confusing because most players are more accustomed to draw-then-play.)  Towards the end of the game, if there are no more cards to draw, then you simply skip that step.&lt;/p&gt;&lt;p&gt;Once you have played a card on a stone, you're stuck with it.  There is no way to take it back or replace it or cover it up.  Most of the time you will not have all the cards that you want when you start playing a particular three-card group.  The tension in the game comes from trying to avoid commiting to a particular kind of group for as long as possible.  For example, suppose you've played the blue 6 on a stone, and now you have the blue 5 and the red 6 in your hand.  If you play the blue 5 next, then you are commiting to trying for a straight flush.  If you play the red 6 next, then you are commiting to trying for three-of-a-kind.  The straight flush is stronger, but there are only two other cards in the deck that will complete the straight flush (the blue 4 or the blue 7).  On the other hand, there are four other 6's in the deck, so you have a better chance of completing the three-of-a-kind.  What you will probably do is delay playing on this stone by playing somewhere else, but that just means making a commitment there instead of here.  If you do play on this stone, be prepared for the frustration of drawing exactly the card you needed for the group that you just ruled out!&lt;/p&gt;&lt;p&gt;(Technically, if you play the blue 5 on the blue 6, you are not commiting to trying for a straight flush.  Any other blue will complete a flush, and any 4 or 7 will complete a straight.  However, you almost never want a plain flush or a plain straight until close to the end of the game, because they are just too easy to beat.)&lt;/p&gt;&lt;p&gt;Each stone is awarded when both three-card groups are complete.  However, there is a twist here that may appeal to programmers, who tend to excel at logical thinking.  You can also claim a stone early if you can &lt;i&gt;prove&lt;/i&gt; that your opponent can't beat your hand.  For example, suppose you have three 7's on your side of a stone, and your opponent has the green 1 and the green 2 on his side.  If the green 3 has already been played somewhere else, then there is no way your opponent can complete the straight flush.  The best he could do would be a plain flush, which would lose to your 7's.  Therefore, you can claim the stone without waiting for him to complete his group.&lt;/p&gt;&lt;p&gt;Note that the proof must be accomplished with cards that have already been played.  In the above example, if you were holding the green 3, you could not claim the stone until you played it.  Sometimes this means that you will play a card in a place where you would prefer not to, just to be able to claim a stone elsewhere.&lt;/p&gt;&lt;p&gt;Claiming stones early is important for two reasons.  First, there are situations where both players can fulfill the victory conditions, so it is just a matter of who claims the stones first.  For example, both players might be able to get three adjacent stones, or one might be able to get three adjacent stones while the other can get five stones altogether.&lt;/p&gt;&lt;p&gt;Second, and getting back to the theme of this recommendation, claiming a stone early helps you keep the pressure on your opponent.  Once a stone has been claimed, neither player can play cards on that stone anymore, even if they have room to do so.  You never want to give your opponent an easy place to dump a card.  Not only does that let them rid themselves of a useless card&amp;#8212;when you can only hold six cards at a time, freeing up an otherwise useless slot is huge&amp;#8212;but more importantly it lets them avoid making a commitment someplace else.&lt;/p&gt;
&lt;h3&gt;How to get it&lt;/h3&gt;&lt;p&gt;Schotten Totten can be hard to find in stores.  Fortunately, its sister game, &lt;a href="http://www.boardgamegeek.com/game/760"&gt;Battle Line&lt;/a&gt; is much more widely available.  Battle Line is almost the same game, but with different artwork, with cards numbered 1-10 instead of 1-9, and with 7 cards per hand instead of 6.  Also, Battle Line adds a separate mini-deck of so-called &lt;i&gt;tactics cards&lt;/i&gt;, which let you change the rules in various ways.  For example, one tactics card forces you to play 4 cards on each side of a particular stone instead of 3.  (Actually, newer editions of Schotten Totten include the tactics cards as well.)&lt;/p&gt;&lt;p&gt;Personally, I like Schotten Totten better.  I prefer the smaller, more claustrophobic scale.  Also, I prefer the game without the tactices cards, which make the game too chaotic.  Fortunately, if you get Battle Line you can experiment with or without the tactics cards, with our without the 10's, and with 7-card or 6-card hands, to see which way you like it better.&lt;/p&gt;&lt;p&gt;A good place to look for both games is &lt;a href="http://www.boardgameprices.com/"&gt;BoardGamePrices.com&lt;/a&gt;, which summarizes prices and availability at a host of on-line game retailers.&lt;/p&gt;&lt;p&gt;If you want to try the game out before buying it, there are excellent implementations of Schotten Totten at both &lt;a href="http://www.flexgames.com/"&gt;flexgames&lt;/a&gt; and &lt;a href="http://www.yucata.de/"&gt;Yucata.de&lt;/a&gt;.  (The latter site defaults to German but can be set to English by clicking on the flag.)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-4969461440807974839?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/4969461440807974839/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=4969461440807974839' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4969461440807974839'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4969461440807974839'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/games-for-programmers-schotten.html' title='Games for Programmers: Schotten Totten/Battle Line'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://3.bp.blogspot.com/_HOXl0OgNHo0/R82L4skNSMI/AAAAAAAAAAc/mBHoCiI8fRU/s72-c/schottenbox.jpg' height='72' width='72'/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-4170275741249089388</id><published>2008-03-06T20:57:00.000-05:00</published><updated>2008-03-06T20:57:28.189-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><title type='text'>Get the job done, but what is the job?</title><content type='html'>&lt;p&gt;One of my most memorable conversations with a student happened a few years ago.  I was grading a programming project, and something in one of the project documents struck me.  At our school, students are required to document help from other students in some detail.  One pair described getting help from another student, call him K.  Apparently, K was telling them how to do something, but they weren't understanding him fast enough.  He got impatient, grabbed the keyboard, and starting typing in the code for them.&lt;/p&gt;&lt;p&gt;I was flabbergasted by this description.  How could K have possibly believed that this was appropriate?  I knew the class that he was just about to get out of, so I met him there and took him into an empty classroom.&lt;/p&gt;&lt;p&gt;For at least five minutes, we talked completely past each other.  He didn't understand why I was upset, and I didn't understand why he seemed to believe he had done a genuinely good thing.  Obviously, there were some unspoken assumptions on both sides that were preventing us from communicating.&lt;/p&gt;&lt;p&gt;Eventually, I realized what was going on.  He had been taught that the bottom line was getting the job done.  That was the most important thing, and he believed that what we teachers wanted from students was for them to get the job done.  Helping his buddies get the job done was, in his eyes, no less than the responsible thing to have done, a positive act of virtue.&lt;/p&gt;&lt;p&gt;Aha!  With this realization, and with his phrase of &amp;ldquo;getting the job done&amp;rdquo;, I finally had the wedge I needed to get through to him.&lt;/p&gt;&lt;p&gt;&amp;ldquo;What was the job on this project?&amp;rdquo;, I asked him.&lt;/p&gt;&lt;p&gt;&amp;ldquo;To complete a working program&amp;rdquo;, he replied.&lt;/p&gt;&lt;p&gt;&amp;ldquo;No, it wasn't&amp;rdquo;, I said.  Utter confusion covered his face.  &amp;ldquo;Think about it.  I already have a solution to this project.  Why would I need a dozen student implementations?  I'm pretty sure that mine is going to be less buggy, faster, and better documented than any of yours.&amp;rdquo;&lt;/p&gt;&lt;p&gt;&amp;ldquo;But...&amp;rdquo;  The first signs of doubt.&lt;/p&gt;&lt;p&gt;&amp;ldquo;So, if I don't really care about your implementations, then why did I have you all do this project?  What &lt;i&gt;do&lt;/i&gt; I care about?  &lt;i&gt;What was the job?&lt;/i&gt;&amp;rdquo;&lt;/p&gt;&lt;p&gt;K frowned in concentration.  It's never an easy thing when somebody tries to dismantle your basic assumptions.  To his credit, he didn't just shut down, but actively struggled to understand what I was saying.  He started to speak and stopped a few times.  He was almost there, but couldn't quite articulate it.&lt;/p&gt;&lt;p&gt;&amp;ldquo;Learning&amp;rdquo;, I finally said.  &amp;ldquo;The job was learning.  The implementation was only a way to trigger that learning.  But the implementation doesn't really matter, it's the learning that I care about.&amp;rdquo;&lt;/p&gt;&lt;p&gt;He got it.  He understood why, from my point of view, typing in code for the other students was not helping them get the job done, but instead was actively hindering the learning that was the real job.&lt;/p&gt;
&lt;p&gt;As we wound down, he mentioned a different teacher he had had the previous two semesters.  The other teacher had a grading policy where you get credit for an assignment only when it is completely correct.  If your assignment has flaws, then you redo it until it's correct, losing points with each resubmission.  For somebody like K, who strongly believes in getting the job done, this policy just reinforces the idea that finishing the program is the job.  I know this wasn't the other teacher's intent, but I can certainly see how it could be taken that way.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-4170275741249089388?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/4170275741249089388/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=4170275741249089388' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4170275741249089388'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4170275741249089388'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/get-job-done-but-what-is-job.html' title='Get the job done, but what is the job?'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-3638279325415766701</id><published>2008-03-01T22:48:00.001-05:00</published><updated>2008-03-01T22:49:17.879-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='TradeMaximizer'/><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>What the heck is a math trade?</title><content type='html'>&lt;p&gt;Many sites exist for trading objects or services of various kinds&amp;#8212;my favorite example is a site for trading &lt;a href="http://www.oddshoe.org/"&gt;right or left shoes&lt;/a&gt;.  Over on &lt;a href="http://www.boardgamegeek.com/"&gt;BoardGameGeek&lt;/a&gt;, there is a very active community of users who trade board games.  The site lets you list games that you are offering and games that you want, and then automatically finds possible matches.  Even with this support, however, finding and negotiating individual trades can be tedious.  Enter &lt;i&gt;Math Trades&lt;/i&gt;, which have been running regularly on BoardGameGeek for several years.&lt;/p&gt;&lt;p&gt;One frequent difficulty with individual trades is that, although you have something I want, I might not have what you want.  What if we were able to get a third person involved?  Suppose you have what I want, Tina has what you want, and I have what Tina wants.  Then we can arrange a three-person swap.  &lt;a href="http://www.swaptree.com/"&gt;SwapTree&lt;/a&gt; is a site that will find such three-way and even four-way trades for you automatically.&lt;/p&gt;&lt;p&gt;But why stop there?  Why not look for five-way loops, or even hundred-way loops?  That's what happens in a &lt;i&gt;Math Trade&lt;/i&gt;.&lt;/p&gt;
&lt;h3&gt;How a math trade works&lt;/h3&gt;
&lt;p&gt;First, a moderator announces the opening of the trade and lays down trade-specific ground rules.  Everybody who is interested in participating lists the items they choose to offer in the trade.  At a pre-determined time, the list closes to new entries.&lt;/p&gt;&lt;p&gt;Next, the participants review all the offers and decide which ones they want.  For each item you are offering, you create a wantlist that says, in essence, &amp;ldquo;I would be willing to trade item 57 (my item), for item 22 or item 34 or item 119 or item 576.&amp;rdquo;  Everybody sends their wantlists to the moderator by the announced deadline.&lt;/p&gt;&lt;p&gt;After a brief period for finding and correcting errors, the moderator runs special math trade software to find the most trades possible.  The moderator then publishes the results, the participants exchange addresses, and drop their items in the mail.&lt;/p&gt;
&lt;h3&gt;A lot of trades&lt;/h3&gt;
&lt;p&gt;Note that the &amp;ldquo;most trades possible&amp;rdquo; can be quite a lot.  The &lt;a href="http://www.boardgamegeek.com/geeklist/28232"&gt;largest math trade to date&lt;/a&gt; involved 2320 items, of which 994 traded.  These 994 items were broken into 7 trade loops, including one monstrous loop of 920 items.  Just imagine standing in a circle with 919 of your closest friends and everyone handing their game to the person on their right!&lt;/p&gt;&lt;p&gt;(Actually, this trade involved 316 users, many of whom were trading multiple items.  So that loop of 920 items wasn't really 920 people.)&lt;/p&gt;&lt;p&gt;Although math trades have been run regularly on BoardGameGeek for almost three years, it is only recently that trades of this size have become possible.  About six months ago, I wrote &lt;a href="https://sourceforge.net/projects/trademax"&gt;TradeMaximizer&lt;/a&gt;, which has become the de facto standard software for math trades.  TradeMaximizer improves on previous software by guaranteeing to find the maximum number of trades possible, and by doing so quickly, in under a minute for the large trade above and in just a few seconds for most trades.  Previous software ran in hours or days, and even then might not find all the trades possible.  I'll describe TradeMaximizer in detail in an upcoming post.&lt;/p&gt;
&lt;h3&gt;Beyond games&lt;/h3&gt;
&lt;p&gt;There's nothing specific to games in the idea of math trades or in TradeMaximizer.  I know of math trades run for &lt;a href="http://www.melankolia.net/gameblog/archives/2006/05/"&gt;metal CDs&lt;/a&gt; (using earlier software) and for &lt;a href="http://forums.groundspeak.com/GC/index.php?showtopic=176030"&gt;geocoins&lt;/a&gt; (using TradeMaximizer).  If you have run a math trade in another community, or think you might like to, please post a comment here and let us know.  Don't be afraid!  They're easy to run if you keep it relatively small, and a lot of fun.&lt;/p&gt;&lt;p&gt;Probably the coolest application of math trades is for trading...kidneys!&lt;/p&gt;&lt;p&gt;No, this isn't some urban legend about &lt;a href="http://www.snopes.com/horrors/robbery/kidney.asp"&gt;waking up in an ice-filled bathtub&lt;/a&gt;.  This is serious, life-or-death stuff.&lt;/p&gt;&lt;p&gt;When somebody needs a kidney transplant, they can often find a family member or friend who is willing to donate one.  But what happens if the donor's kidney is biochemically incompatible with the intended recipient?  Well, sometimes you can find two such donor-recipient pairs where each donor is compatible with the &lt;i&gt;other&lt;/i&gt; recipient.  By donating to the other recipient, each donor ensures that their intended recipient gets a compatible kidney.  Three-way trades and four-way trades are also possible.  Unlike ordinary math trades, however, larger loops are not supported.  Oh, you can find the loops, but doctors won't perform the surgeries because the risks of something going wrong (such as somebody backing out at the last minute) are just too great.&lt;/p&gt;&lt;p&gt;A &lt;a href="http://www.cmu.edu/news/archive/2007/June/june11_kidney.shtml"&gt;trio at CMU&lt;/a&gt; implemented a system that is now being used to find matches in a national list of donors every two weeks by the &lt;a href="http://www.paireddonation.org/"&gt;Alliance for Paired Donation&lt;/a&gt;.  Their system differs from an ordinary BoardGameGeek-style math trade in two fundamental ways.  One is the deliberate limit on the sizes of trade loops (which actually makes the problem &lt;i&gt;harder&lt;/i&gt;, not easier).  The other is the presence of &lt;a href="http://www.hopkinsmedicine.org/transplant/Programs/InKTP/altruistic.html"&gt;altruistic donors&lt;/a&gt;&amp;#8212;donors who give their kidneys to strangers without asking for a kidney for a friend or loved one in return.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-3638279325415766701?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/3638279325415766701/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=3638279325415766701' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/3638279325415766701'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/3638279325415766701'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/03/what-heck-is-math-trade.html' title='What the heck is a math trade?'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-1477867183672088909</id><published>2008-02-25T12:55:00.003-05:00</published><updated>2008-02-25T22:09:30.803-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>In praise of mandatory indentation for novice programmers</title><content type='html'>&lt;p&gt;About four years ago, I created my own programming language for teaching. I'll probably write more about this language at some other time, but for now I want to focus on one feature of the language: the use of mandatory indentation. My experience with this aspect of the language has been so overwhelmingly positive that &lt;i&gt;I will never again voluntarily use a language without mandatory indentation for teaching novice programmers.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;Of course, sometimes the choice of language is not under my control. Even when it is, there are always many different factors that go into that choice. But no other single factor I've run across has greater significance. For example, programming language afficionados spend endless hours arguing about static vs dynamic typing, or functional vs object-oriented languages, or strict vs lazy evaluation, or...you get the idea. Those differences can indeed be important, but more so for experienced programmers working on large projects than for novice programmers working on classroom projects. None of these differences individually comes close to the issue of indentation.&lt;/p&gt;&lt;p&gt;I say this with some pain, because I'm a programming languages guy myself. I've taken part in some of those arguments, and spent many hours contemplating the relative merits of many much deeper programming language properites. It hurts me to say that something so shallow as requiring a few extra spaces can have a bigger effect than, say, Hindley-Milner type inference. I wish it weren't so, but that is what my classroom experience tells me, loudly and unambiguously.&lt;/p&gt;
&lt;h3&gt;Why not mandatory indentation?&lt;/h3&gt;
&lt;p&gt;The vast majority of languages don't make indentation mandatory. Instead, they usually use explicit syntax to indicate block structure, such as &lt;tt&gt;{&lt;/tt&gt; and &lt;tt&gt;}&lt;/tt&gt;, or &lt;tt&gt;BEGIN&lt;/tt&gt; and &lt;tt&gt;END&lt;/tt&gt;. Yet, if you look at well-written programs in those languages, they are almost always indented sensibly. Furthermore, there's remarkably little disagreement as to what “sensible” indentation looks like. So why not make that sensible indentation mandatory? There are several reasons that are often put forth:
&lt;ul&gt;&lt;li&gt;&lt;b&gt;It's weird.&lt;/b&gt; Because the vast majority of languages don't use it, most programmers aren't used to the idea. Therefore, there's an initial sense of unease.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;It messes up the scanner/parser.&lt;/b&gt; True, mandatory indentation is harder to deal with using traditional scanners and parsers based strictly on regular expressions and context-free grammars, respectively. But it's usually trivial to modify the scanner to keep track of indentation and issue an INDENT token when indentation increases, and one or more OUTDENT tokens when indentation decreases. The parser can then treat these tokens just like normal BEGIN/END keywords.
In this approach the scanner is no longer based strictly on regular expressions, but most scanners aren't anyway (for example, when dealing with nested comments). Using the INDENT/OUTDENT tokens, the parser can still be based strictly on context-free grammars.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Don't try to take away my freedom!&lt;/b&gt; Programmers are a pretty libertarian bunch. Anytime somebody tries to impose rules that they follow 99% of the time anyway, they always focus on the 1% exceptions. For indentation, these exceptions often involve what to do with lines that are too long. So yeah, a language with mandatory indentation shoud deal gracefully with that issue. Or sometimes the exceptions involve code that is nested 20 levels deep. But these cases are almost always easy to rewrite into an equivalent but shallower structure. One place where I tend to deliberately break indentation rules is with temporary debugging output. I often leave such print statements unindented, so that they're easier to find when it's time to take them out. This is convenient, but I can certainly live without it.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;I don't &lt;i&gt;want&lt;/i&gt; people to be able to read my code!&lt;/b&gt; Maybe some people view obfuscated code as job security. As a different example, the former champion in the &lt;a href="http://www.topcoder.com/tc"&gt;TopCoder&lt;/a&gt; programming contest, John Dethridge, was famous for never indenting. Why? Because in TopCoder, there is a “challenge” phase, where other competitors look at your code and try to find bugs. So there's an incentive to make your code hard for other competitors to understand. I remember teasing him about this once, and he said laughingly “Beware my left-justified fury!” I replied that I'd be more afraid if his fury was &lt;i&gt;right&lt;/i&gt; justified.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;It doesn't scale.&lt;/b&gt; As programs get bigger, both in lines of code and in number of programmers, you run into more mismatches in indentation. For example, you might want to move or copy a loop that was nested 5 levels deep to another location nested 3 levels deep. Or you might need to integrate code written by programmers that used different numbers of spaces per indentation level. Refactoring tools can certainly help here. But, you know, if you're the sort of programmer who would leave the indentation messed up when you moved that loop, just because your language didn't require you to fix it, then I probably don't want to work with you anyway.&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;What about novices?&lt;/h3&gt;
&lt;p&gt;Most of the objections above don't really apply to novices. Programming is new to them so it's all weird anyway. They have no idea what scanners and parsers are. As teachers, we already take away a lot of their freedoms anyway, and we certainly want them to care if somebody (namely us!) can read their code. And novices are usually not going to be writing large enough programs for the scaling issues to be a big problem.&lt;/p&gt;&lt;p&gt;Ok, but what are the benefits for novices?
&lt;ul&gt;&lt;li&gt;&lt;b&gt;They are already used to the idea of indentation.&lt;/b&gt; Both from writing outlines in English class and from nested bullet lists in the (&lt;a href="http://okasaki.blogspot.com/2008/01/why-i-dont-use-powerpoint-for-teaching.html"&gt;almost&lt;/a&gt;) ubiquitous PowerPoint, novices already have experience with the idea of indicating grouping using indentation. This makes such languages much easier for novices to learn. In contrast, explicit markers such as curly braces or BEGIN/END keywords are something novices have much less experience with. However natural such markers might seem to &lt;i&gt;us&lt;/i&gt;, they are not natural for novices, and are a constant source of mistakes. (Worse, a typical novice strategy for dealing with those mistakes is to randomly insert or delete braces until it compiles—a strategy Peter Lee used to call “programming by random perturbation”.)&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Less is more.&lt;/b&gt; Or, put another way, smaller is better. To the novice, a fifteen-line program is less intimidating than a twenty-line program, a program that fits on one page is much easier to understand than a program that spans multiple pages. Those extra lines taken up by explict braces or BEGIN/END keywords really add up. Even if you use a style that puts a { at the end of the previous line, the } still usually goes on a line by itself. I shudder now everytime I look at a Java program and see a code fragment like&lt;pre&gt;             ...
             }
           }
         }
       }
     }
   }&lt;/pre&gt;
Note that I am &lt;b&gt;not&lt;/b&gt; advocating compressing everything into as few lines as possible (a la &lt;a href="http://perlgolf.sourceforge.net/"&gt;Perl Golf&lt;/a&gt;). Nor am I saying that all redundancy is bad. But in this case, the redundancy of explicit markers was hurting more than it was helping.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Mandatory indentation promotes good habits.&lt;/b&gt; I've taught plenty of novices in languages that did not require indentation. If the language doesn't require it, they won't do it, or at least not consistently. If they are using an IDE that indents for them, fine, but sometimes they need to write code in a primitive editor like Notepad, and then they just won't bother. Even if I require the final submission to be properly indented, all too often they will do all their development without indentation, and then indent the code just before turning it in (kind of like the typical novice approach to commenting). Of course, indenting after the fact means that they don't get any of the benefits from indenting their code, such as making debugging easier. &lt;p&gt;On the other hand, if the language makes indentation mandatory, then the novice needs to keep their indentation up to date during the entire development cycle, so they will reap those benefits. Since I started using this language, I've also noticed improved indentation habits even when students switch to other languages without mandatory indentation. I can at least hope that this habit is permanent, although I have no evidence to back that up.&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;A surprise&lt;/h3&gt;
&lt;p&gt;I was shocked by how much the mandatory indentation seemed to help my students.  I did not come into this expecting much of a change at all.  I had experience with mandatory indentation in a couple of languages (most notably Haskell), and I had found it to be a pleasant way to code.  Also, I had heard good things about people using Python in the classroom.  However, I was by no means a convert at the time that I was designing my language.&lt;/p&gt;&lt;p&gt;I had two motivations for making indentation mandatory in the language.  First, this language was designed to be the second language most of the students saw, and I wanted to expose them to a range of language ideas that they had not seen before.  For example, their first language used static typing so I made my language use dynamic typing.  Similarly, their first language did not make indentation mandatory, so I took the opposite route in my language.  My second motivation was simply that I was annoyed.  I was tired of students coming to me with code what was either completely unindented or, worse, randomly indented.  I figured that making the compiler enforce indentation was the surest way to stop this.&lt;/p&gt;&lt;p&gt;Imagine my surprise when I started teaching this language and found the students picking it up faster than any language I had ever taught before.  As fond as I am of the language, I'm certainly under no illusions that it's the ultimate teaching language.  After carefully watching the kinds of mistakes the students were and were not making, I gradually realized that the mandatory indentation was the key to why they were doing better.  This seemed to manifest itself to two ways, one obvious and one more subtle.  The obvious way was that they were simply spending much less time fighting the syntax.&lt;/p&gt;&lt;p&gt;The more subtle way was that they appeared to be finding it easier to hold short code fragments in their head and figure out exactly what the fragment was doing.  I conjecture that there may be some kind of &lt;a href="http://en.wikipedia.org/wiki/The_Magical_Number_Seven,_Plus_or_Minus_Two"&gt;seven-plus-or-minus-two&lt;/a&gt; phenomenon going on here, where adding extra lines to a code fragment in the form of explicit braces or BEGIN/END keywords pushes the code fragment above some size limit of what novices can hold in their heads.  This wouldn't affect expert programmers as much, because they see beneath the braces to the &lt;a href="http://en.wikipedia.org/wiki/Chunking_%28psychology%29"&gt;chunks&lt;/a&gt; underneath, but novices live at the level of syntax.&lt;/p&gt;&lt;p&gt;Whatever the explanation, I'm now a convert to the power of mandatory indentation for novices.  I've never taught Python, but I suspect those who have may have had similar experiences.  If so, I'd love to hear from you.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-1477867183672088909?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/1477867183672088909/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=1477867183672088909' title='40 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1477867183672088909'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1477867183672088909'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/02/in-praise-of-mandatory-indentation-for.html' title='In praise of mandatory indentation for novice programmers'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>40</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-5849894645265553132</id><published>2008-02-14T11:08:00.002-05:00</published><updated>2008-02-14T11:11:48.846-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='games'/><title type='text'>Games for Programmers: Zendo</title><content type='html'>&lt;p&gt;&lt;i&gt;In addition to teaching and programming, I also enjoy playing board games. This is the first in an irregular series of game recommendations for programmers. Of course, you don't have to be a programmer to enjoy these games, but if you are a programmer, then I think there's a pretty good chance that you'll like them.&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="http://www.boardgamegeek.com/game/6830"&gt;Zendo&lt;/a&gt; is a game about debugging. Ok, it's not really about debugging, but you'll see what I mean in a moment.&lt;/p&gt;
&lt;p&gt;Zendo is a logic game played with a bunch of &lt;a href="http://www.looneylabs.com/whybuy/treehouse.html"&gt;Icehouse&lt;/a&gt; pieces (plastic pyramids in several different colors and sizes) and some markers.&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://1.bp.blogspot.com/_HOXl0OgNHo0/R7NHYfheVwI/AAAAAAAAAAM/Eby3_0LeeAM/s1600-h/zendo.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5166551683628422914" style="MARGIN: 0px 0px 10px 5px; CURSOR: hand" alt="Icehouse pieces and markers" src="http://1.bp.blogspot.com/_HOXl0OgNHo0/R7NHYfheVwI/AAAAAAAAAAM/Eby3_0LeeAM/s320/zendo.jpg" border="0" /&gt;&lt;/a&gt;&lt;br&gt;(photo by &lt;a href="http://www.boardgamegeek.com/user/Terraliptar"&gt;Terraliptar&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;During the game, pyramids will be placed in groups (called &amp;ldquo;koans&amp;rdquo;) that either satisfy or don't satisfy some secret rule. The players try to figure out the rule based on these examples. For example, consider the following group:&lt;/p&gt;
&lt;p align="center"&gt;&lt;a href="http://2.bp.blogspot.com/_HOXl0OgNHo0/R7NJnvheVxI/AAAAAAAAAAU/3YSaJgWOnAs/s1600-h/zendo1.jpg"&gt;&lt;img id="BLOGGER_PHOTO_ID_5166554144644683538" style="CURSOR: hand" alt="" src="http://2.bp.blogspot.com/_HOXl0OgNHo0/R7NJnvheVxI/AAAAAAAAAAU/3YSaJgWOnAs/s320/zendo1.jpg" border="0" /&gt;&lt;/a&gt;&lt;br&gt;(photo by &lt;a href="http://www.boardgamegeek.com/user/toulouse"&gt;Ted Alspach&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;This group might satisfy the rule “at least one piece off the table” or “exactly one tilted piece” or “fewer than two green pieces” or “contains pieces of three different sizes”. It would not satisfy the rule “no two pieces of the same color”.&lt;/p&gt;
&lt;p&gt;One player is designated as the &lt;i&gt;master&lt;/i&gt;, who chooses the secret rule and judges whether proposed groups satisfy the rule. The master initially sets out one group that satisfies the rule (marked with a white stone), and one that doesn't (marked with a black stone). The other players take turns proposing groups, which the master then marks with white or black stones. Later in the game, players try to guess the rule, based on the evidence they've seen. If a guess is correct, that player wins the round, and a new master is chosen for the next round. If a guess is incorrect, then the master creates a counter-example, either a group the satisfies the secret rule but not the player's rule, or a group that satisfies the player's rule but not the secret rule. Either way, the master marks the counter-example with the appropriately colored stone.&lt;/p&gt;
&lt;p&gt;That's the basics of the game.  There are a few more details that can be found in the &lt;a href="http://www.wunderland.com/WTS/Kory/Games/Zendo/HowToPlay.html"&gt;complete Zendo rules&lt;/a&gt;.  (That site also offers a fascinating &lt;a href="http://www.wunderland.com/WTS/Kory/Games/Zendo/DesignHistory.html"&gt;design history&lt;/a&gt; of the game.)&lt;/p&gt;
&lt;p&gt;As a player, you are constantly coming up with possible rules and checking whether they are consistent with the examples that are already on the table.  Often you will have more than one possible rule in mind.  When it's your turn, you try to design a group that will help narrow down the choices.  Ideally, you want a make your group so that either a positive or a negative answer will support some possible rules and deny others.&lt;/p&gt;
&lt;p&gt;The primary challenge as master is coming up with a good secret rule, one that is not too hard and not too easy.  Of course, too hard and too easy will depend on who you are playing with.  &lt;a href="http://www.looneylabs.com/"&gt;Looney Labs&lt;/a&gt; sells a pack of &lt;a href="http://www.looneylabs.com/OurStores/product.html?ProductID=276&amp;List=Accessories"&gt;Zendo rule cards&lt;/a&gt; to get you started.  These rules are fairly easy and are perfect for those new to the game.  Eventually, you will want to start creating your own rules.&lt;/p&gt;
&lt;h3&gt;Debugging&lt;/h3&gt;
&lt;p&gt;Debugging is a fundamental skill of the programmer.  When its your own bug or you're operating under severe time pressure, negative emotional reactions can make debugging quite stressful.  But when you are helping somebody else debug their code, it can be quite fun, kind of like a logic puzzle.&lt;/p&gt;
&lt;p&gt;There are two basic approaches to debugging; most debugging sessions combine both.  In one approach, you step through the code, re-thinking each line and looking for something suspicious.&lt;/p&gt;
&lt;p&gt;In the other approach, you look at the observable evidence&amp;#8212;for &lt;i&gt;this&lt;/i&gt; input, it's producing &lt;i&gt;that&lt;/i&gt; output, when it should be producing &lt;i&gt;this other&lt;/i&gt; output, or the web site crashes every day between 5pm and 6pm&amp;#8212; and try to come up with a hypothesis for what might be going wrong. For example, you might hypothesize that something is going wrong when two clients happen to have the same name, or that somebody is mixing up row-column coordinates with X-Y coordinates.  Often you try to come up with an experiment that might confirm or deny your hypothesis, or help select between several competing hypotheses.   Once you have a fairly solid hypothesis, you can usually narrow down where in the code to go looking for the error.&lt;/p&gt;
&lt;p&gt;It's this latter approach to debugging that Zendo captures so well, that of making and testing and refining and discarding hypotheses.&lt;/p&gt;
&lt;p&gt;Of course, that's the perspective of a computer scientist.  Other kinds of scientists might prefer to think of &lt;a href="http://www.boardgamegeek.com/thread/154012"&gt;Zendo in terms of the scientific method&lt;/a&gt;.
&lt;h3&gt;How to get it&lt;/h3&gt;
&lt;p&gt;Zendo used to be sold in a nice boxed set, but that is long out of print.  In fact, I didn't get my copy until after it was already out of print.  I got it as a gift from my &lt;a href="http://www.boardgamegeek.com/"&gt;BoardGameGeek&lt;/a&gt; Secret Santa, a charming annual tradition where hundreds of boardgamers anonymously send Christmas presents (games, naturally) to other gamers around the world, usually gamers that the sender doesn't even know.&lt;/p&gt;
&lt;p&gt;You can still buy the pyramids from &lt;a href="http://www.looneylabs.com/"&gt;Looney Labs&lt;/a&gt;, where they are sold as &lt;a href="http://www.looneylabs.com/whybuy/treehouse.html"&gt;Treehouse sets&lt;/a&gt;.  You would need at least four sets to play Zendo&amp;#8212;five would be better.  It's kind of expensive that way, but fortunately there are a whole bunch of &lt;a href="http://www.icehousegames.org/wiki/index.php?title=Existing_Games"&gt;other games&lt;/a&gt; you can play with the pieces.  You would still need a set of markers, but poker chips or coins in several denominations work fine.&lt;/p&gt;
&lt;p&gt;In fact, with only minor modifications, it's easy to improvise a set of pieces for Zendo out of common household objects, such as &lt;a href="http://www.boardgamegeek.com/image/74058"&gt;bottles of beer&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-5849894645265553132?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/5849894645265553132/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=5849894645265553132' title='6 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5849894645265553132'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/5849894645265553132'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/02/games-for-programmers-zendo.html' title='Games for Programmers: Zendo'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media='http://search.yahoo.com/mrss/' url='http://1.bp.blogspot.com/_HOXl0OgNHo0/R7NHYfheVwI/AAAAAAAAAAM/Eby3_0LeeAM/s72-c/zendo.jpg' height='72' width='72'/><thr:total>6</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-4783688804692941885</id><published>2008-02-08T13:08:00.000-05:00</published><updated>2008-02-08T13:12:53.039-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='functional programming'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Ten Years of Purely Functional Data Structures</title><content type='html'>&lt;p&gt;In 1998, I published a book called &lt;b&gt;Purely Functional Data Structures&lt;/b&gt;.  Ten years later, the book is still selling well.  (Every time I get a royalty check, my wife the skeptic says &amp;ldquo;People are &lt;i&gt;still&lt;/i&gt; buying that?!&amp;rdquo;)  The ten-year anniversary seems like a good time to reflect back on my experience with this book.&lt;/p&gt;
&lt;h3&gt;Origins&lt;/h3&gt;
&lt;p&gt;My first introduction to functional programming was at Carnegie Mellon University, where I worked for &lt;a href="http://www.cs.cmu.edu/~petel/"&gt;Peter Lee&lt;/a&gt; and Phil Koopman on an implementation of a subset of &lt;a href="http://www.haskell.org/"&gt;Haskell&lt;/a&gt; (called &amp;ldquo;&lt;a href="http://en.wikipedia.org/wiki/Eddie_Haskell"&gt;Eddie&lt;/a&gt;&amp;rdquo;), written in &lt;a href="http://www.smlnj.org/"&gt;Standard ML&lt;/a&gt;.  So right from the very beginning, I was working with a mix of strict and lazy evaluation.&lt;/p&gt;
&lt;p&gt;I've always been fascinated by data structures, and I soon realized that something was strange about data structures in these two languages.  On the one hand, when they worked, data structures were more pleasant to work with than in any other languages I had ever used before.  On the other hand, sometimes they just didn't work.&lt;/p&gt;
&lt;p&gt;The issue was &lt;i&gt;immutability&lt;/i&gt;.  In pure functional programming, all data structures are immutable, meaning that they cannot be changed once created.  Of course, data structures frequently need to be changed, so what happens is that you create a new copy of the data structure that incorporates the change, without actually modifying the old copy.  This can often be done efficiently by having the new structure share large chunks of the old one.  For example, stacks are trivial to implement this way.  Tree-like structures such as binary search trees and many kinds of priority queues are almost as easy.&lt;/p&gt;
&lt;p&gt;However, some common data structures, such as FIFO queues and arrays, can actually be quite difficult to implement this way.  Some people take this as a sign that functional languages are impractical.  However, it's not the fault of functional programming per se, but rather of immutability.  Immutable data structures are just as awkward to implement in conventional languages such as Java.  (Of course, immutable data structures also offer huge advantages, which is why, for example, strings are immutable in Java.)&lt;/p&gt;
&lt;p&gt;In 1993, I ran across an &lt;a href="http://citeseer.ist.psu.edu/117501.html"&gt;interesting paper&lt;/a&gt; by Tyng-Ruey Chuang and Benjamin Goldberg, showing how to implement efficient purely functional queues and double-ended queues.  Their result was quite nice, but rather complicated, so I started looking for a simpler approach.  Eventually, I came up a much simpler approach based on lazy evaluation, leading to my &lt;a href="http://citeseer.ist.psu.edu/158610.html"&gt;first paper&lt;/a&gt; in this area.  (When I say simpler here, I mean simpler to implement&amp;#8212;the new structure was actually harder to analyze than Chuang and Goldberg's.)&lt;/p&gt;
&lt;p&gt;Almost immediately after my paper on queues, I worked on a paper about &lt;a href="http://citeseer.ist.psu.edu/okasaki95purely.html"&gt;functional arrays&lt;/a&gt;, here called &lt;i&gt;random-access lists&lt;/i&gt; because they combined the extensibility of lists with the random access of arrays.  (Because the lead time on journal papers is longer than the lead time for conferences, this paper actually appeared before the paper on queues, even though it was written later.)  The approach I used, which turned out to be very similar to one used earlier by Gene Myers, was based on properties of an obscure number system called &lt;i&gt;skew binary numbers&lt;/i&gt;.  This marked the beginning of a second theme of my work, that of designing implementations of data structures in analogy to number systems.  For example, inserting an element into a data structure is similar to incrementing a number, and merging two data structures is similar to adding two numbers.  I called this approach &lt;i&gt;numerical representations&lt;/i&gt;.  The idea was to choose or create a number system with the properties you want (such as constant-time addition), and then build the data structure on top of that.  The advantage of this approach is that you can often do the hard work in a simplified setting, where you don't have to worry about carrying around the actual data in your data structure.&lt;/p&gt;
&lt;p&gt;Amusingly, this paper marked the second round of a circle dance between Rob Hoogerwoord, Tyng-Ruey Chuang, and me.  First, Hoogerwoord published a paper on functional queues, then Chuang, then me.  And again with functional arrays, first Hoogerwoord published a paper, then Chuang, then me.&lt;/p&gt;
&lt;p&gt;Around this time, I was looking for a thesis topic (that period that John Reynolds describes as &amp;ldquo;making even the best student look bad&amp;rdquo;).  Fortunately, my advisor Peter Lee had patience with me during this search.  I considered a bunch of topics related to functional programming, but none of them seemed right.  I was enjoying the work I was doing with functional data structures, but there didn't really seem to be enough meat there for a dissertation.  That changed one day during a walk in the snow.&lt;/p&gt;
&lt;p&gt;I had become fascinated by the idea of concatenation (appending two lists).  This is trivial to do in conventional languages using, say, doubly-linked lists.  But it's much harder to do efficiently with immutable lists.  I thought that I had come up with a new approach, so I made an appointment to talk to Danny Sleator about it.  He had been involved in some of the early work in this topic (along with Neil Sarnak and Bob Tarjan), and his office was just a few floors below mine.  The day before the meeting, I realized that my approach was completely broken.  Afraid of looking like an idiot, I went into a frenzy, playing with different variations, and a few hours later I came up with an approach again based on lazy evaluation.  I was sure that this approach worked, but I had no idea how to prove it.  (Again, this was a case where the implementation was simple, but the analysis was a bear.)  My wife had our car somewhere else that day, so I ended up walking home.  The walk usually took about 45 minutes, but it was snowing pretty hard, so it took about twice that long.  The whole way home I thought about nothing but how to analyze my data structure.  I knew it had something to do with amortization, but the usual techniques of amortization weren't working.  About halfway home, I came up with the idea of using &lt;i&gt;debits&lt;/i&gt; instead of credits, and by the time I got home the entire framework of how to analyze data structures involving lazy evaluation had crystallized in my head.&lt;/p&gt;
&lt;p&gt;With this framework in mind, I now believed that there was enough meat there for a dissertation, and I sailed through my thesis proposal and, about a year later, my thesis defense.&lt;/p&gt;
&lt;h3&gt;The Book&lt;/h3&gt;
&lt;p&gt;After my defense, Peter Lee suggested that I try to publish my dissertation as a book.  He contacted two publishers he had worked with before, and one of them, Lauren Cowles of Cambridge University Press, bit.&lt;/p&gt;
&lt;p&gt;The process of turning my dissertation into a book was pure joy.  I thought that the basic organization of my dissertation was pretty solid, so mostly I was able to focus on adding and adjusting things to make it work better as a book.  For example, I no longer had the constraint from my dissertation of having to focus on original work, so I was free to add data structures that had been developed by other people.&lt;/p&gt;
&lt;p&gt;The main additions were expanded introductory material (such as my simplification of red-black trees, which was developed a few weeks after my thesis defense in a series of emails with Richard Bird), exercises, and an appendix including all the source code in Haskell (the main text used source code in Standard ML).&lt;/p&gt;
&lt;p&gt;After several months of hacking, I was able to ship off a giant Postscript file to Lauren Cowles, and that was that.&lt;/p&gt;
&lt;p&gt;Well, not quite.  Lauren asked me what I wanted for cover art.  My wife was an avid quilter, and I liked the idea of having a suitably geeky quilt pattern on the cover.  I adapted a quilt pattern called &lt;i&gt;Flying Geese&lt;/i&gt;, and sent a sketch to Lauren, who got a graphic artist to draw up the final version.  I was quite happy with it.  Later, I found out that Flying geese was actually the name of a different pattern, and to this day, I don't know the correct name of the pattern.  It looks a little different on the book than in quilts because quilters usually only use two levels of the recursion, but I used three.&lt;/p&gt;
&lt;h3&gt;Reactions&lt;/h3&gt;
&lt;p&gt;Initial reviews were positive and the hardcover edition sold out pretty quickly, so Cambridge University Press released a paperback edition the following year.  I don't know of any courses that used it as the main textbook (it would have to be a pretty specialized course to do that), but several mainstream courses used it as a supplementary textbook.&lt;/p&gt;
&lt;p&gt;Sales were steady but trending downward, until 2004, when a book review by Andrew Cooke appeared on &lt;a href="http://books.slashdot.org/article.pl?no_d2=1&amp;sid=04/02/19/2257203"&gt;Slashdot&lt;/a&gt;.  After that, sales doubled and have stayed at that level for several years.  Of course, I can't be sure this increase was because of Slashdot, but it seems likely.  Thanks, Andrew!&lt;/p&gt;
&lt;p&gt;The most interesting place the book has shown up was in the data of a &lt;a href="http://www.topcoder.com/tc"&gt;TopCoder&lt;/a&gt; programming contest problem involving sorting books on a bookshelf.  It was part of a list of CS textbooks.  (And, no, I wasn't the author of the problem, although I have written some problems for TopCoder.)&lt;/p&gt;
&lt;p&gt;The funniest moment about the book was when I worked at Columbia University.  A potential grad student from an unrelated field in CS was visiting from Germany, and I was talking to him about the department.  When I told him about my research, he said, &amp;ldquo;My roommate has been reading a book about something like that.  I don't remember the name, but do you know which book I mean?&amp;rdquo;  I reached over and pulled my book off the shelf and said, &amp;ldquo;Do you mean this one?&amp;rdquo;  His mouth fell open.&lt;/p&gt;
&lt;p&gt;The most flattering review of the book appeared a few years ago in a &lt;a href="http://jaortega.wordpress.com/2006/03/28/a-haskell-bookshelf/"&gt;blog&lt;/a&gt; by José Antonio Ortega Ruiz, who said&lt;blockquote&gt;&amp;ldquo;The exposition is extremely elegant and synthetic, and i’ve spent many, many hours immersed in its 220 pages (i can’t think of any other programming book with a better signal to noise ratio, really).&amp;rdquo;&lt;/blockquote&gt;Thanks, jao!&lt;/p&gt;
&lt;h3&gt;Complaints&lt;/h3&gt;
&lt;p&gt;Of course, you can't please everybody.  The most common complaints I've heard are&lt;ul&gt;&lt;li&gt;&lt;b&gt;No hash tables.&lt;/b&gt; This was mentioned in the first review of the book on &lt;a href="http://www.amazon.com/gp/product/0521663504/"&gt;Amazon&lt;/a&gt;, which called the lack of hash tables a &amp;ldquo;major omission, likely because they don't fit well into a functional environment.&amp;rdquo;  More than a year later, a second reviewer mentioned that hash tables are in fact in the book, but buried in an exercise.  Both reviewers are correct.  I only gave a very short description of hash tables in an exercise, because there just wasn't that much to say.  A hash table is basically the composition of two finite maps, one approximate and one exact.  The choice of what structures to use for those finite maps are up to you.  Typically, an array is used for the approximate map, but, as the first reviewer noted, arrays do not fit well into a functional environment.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;No delete for red-black trees.&lt;/b&gt; I present my simplified form of red-black trees very early in the book as an introduction to functional data structures, but I only describe insertions, not deletions.  There were two main reasons for that omission.  First, deletions are much messier than insertions, and the introduction did not seem like the right place for a lot of messy details.  Second, and more importantly, probably 95+% of uses of functional red-black trees don't need deletions anyway.  Because the trees are immutable, when you want to delete something, you can simply revert back to a previous version of the tree from before the unwanted item was inserted.  This is almost always both the easiest and the right thing to do.  The exception is when you inserted something else that you want to keep after the item to be deleted, but this is extremely rare.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Why Standard ML?&lt;/b&gt; In the last 10 years, Haskell has become steadily more popular, while Standard ML has largely been replaced by OCaml.  A frequent complaint has been people wishing that Haskell was in the main text, with Standard ML (or OCaml) in the appendix, instead of the reverse.  Even at the time, I debated with myself about the choice of Standard ML, particularly because in some chapters I had to fake extensions to the language, such as lazy evaluation and polymorphic recursion.  I went with Standard ML for two main reasons.  First, I wanted to be able to distinguish between lazy evaluation and strict evaluation, which was much more difficult in Haskell.  Second, I &lt;i&gt;really&lt;/i&gt; wanted to be able to give module signatures for all the common structures (stacks, queues, etc.) that I was going to be revisiting over and over.  You can sort of do this in Haskell, but not cleanly.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Too esoteric/impractical.&lt;/b&gt; Guilty as charged!  I did try to point out a few data structures along the way that were especially practical, but that was not my main focus.  If it was, I certainly would not have included umpteen different implementations of queues!  Instead, I was trying to focus on design techniques, so that readers could use those techniques to design their own data structures.  Many of the example data structures were included as illustrations of those design techniques, not because the examples were particularly practical or valuable by themselves.&lt;/li&gt;&lt;/ul&gt;
&lt;h3&gt;The Future?&lt;/h3&gt;
&lt;p&gt;People sometimes ask me if I'm planning a second edition.  The answer is maybe, but not anytime soon.  I'm still pretty happy with what I said and how I said it, so I don't feel a burning need to go back and correct things.  If I wrote a second edition, it would be to modernize the presentation and to add some new data structures and techniques.  For example, I might include the finger trees of Ralf Hinze and Ross Paterson.&lt;/p&gt;
&lt;p&gt;In terms of the presentation, however, the biggest question would be what language to use.  Standard ML probably doesn't make sense any more, but I'm still not sure Haskell is ready to take over, for the same reasons mentioned above.  I suppose I could switch to OCaml, but I'm not sure that's enough of a change to warrant a new edition.  I have faith that the vast majority of my readers are perfectly capable of making the translation from Standard ML to OCaml themselves.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-4783688804692941885?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/4783688804692941885/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=4783688804692941885' title='17 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4783688804692941885'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/4783688804692941885'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/02/ten-years-of-purely-functional-data.html' title='Ten Years of Purely Functional Data Structures'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>17</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-9028633124467767541</id><published>2008-02-01T09:20:00.000-05:00</published><updated>2008-02-01T09:22:51.994-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Boolean Confusion</title><content type='html'>&lt;p&gt;A big part of learning to program is building up effective mental models for how various logical structures work.  A big part of learning to &lt;i&gt;teach&lt;/i&gt; programming is learning how to diagnose broken or ineffective mental models by reading someone's code.  One common confusion that shows up very clearly in the code of novice programmers is thinking of booleans and control expressions as being somehow two separate things.&lt;/p&gt;&lt;p&gt;By &amp;ldquo;control expressions&amp;rdquo;, I mean the expressions that are used in if-statements and while-loops.  For example, in&lt;pre&gt;
   while (i &amp;lt; 100) {
      ...
   }&lt;/pre&gt;
the control expression is &amp;ldquo;&lt;tt&gt;i &amp;lt; 100&lt;/tt&gt;&amp;rdquo;.  Of course, the value of the control expression is a boolean.  Novices can even tell you that, but they haven't quite internalized it yet.&lt;/p&gt;&lt;p&gt;Suppose you wanted a function to test whether an integer is positive.  An experienced programmer might write&lt;pre&gt;
   boolean isPositive(int n) {
      return n &amp;gt; 0;
   }&lt;/pre&gt;
but a novice programmer would be more likely to write&lt;pre&gt;
   boolean isPositive(int n) {
      if (n &amp;gt; 0) {
         return true;
      }
      else {
         return false;
      }
   }&lt;/pre&gt;
Why?  Because the function is supposed to return a boolean, but the novice doesn't quite believe that &lt;tt&gt;n &amp;gt; 0&lt;/tt&gt; is a boolean&amp;#8212;it's a control expression!&lt;/p&gt;&lt;p&gt;On the flip side, suppose you have a loop being controlled by a boolean variable named &lt;tt&gt;flag&lt;/tt&gt;.  An experienced programmer might write&lt;pre&gt;
   while (flag) {
      ...
   }&lt;/pre&gt;
but a novice programmer would be more likely to write&lt;pre&gt;
   while (flag == true) {
      ...
   }&lt;/pre&gt;
Why?  Because the while-loop needs a control expression, and the novice doesn't quite believe that &lt;tt&gt;flag&lt;/tt&gt; is a control expression&amp;#8212;it's a boolean!  The novice uses the &lt;tt&gt;==&lt;/tt&gt; operator to convert the boolean into a control expression.&lt;/p&gt;&lt;p&gt;In extreme cases, you can even see both cases simultaneously, such as this gem where a public method is checking the state of a private variable&lt;pre&gt;
   public boolean isReady() {
      if (ready == true) {
         return true;
      }
      else {
         return false;
      }
   }&lt;/pre&gt;
What are some programming idioms you've seen that help you diagnose confusions like these?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-9028633124467767541?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/9028633124467767541/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=9028633124467767541' title='31 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/9028633124467767541'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/9028633124467767541'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/02/boolean-confusion.html' title='Boolean Confusion'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>31</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-8142011129191395151</id><published>2008-01-23T10:00:00.000-05:00</published><updated>2008-01-24T08:58:18.478-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='computational thinking'/><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><category scheme='http://www.blogger.com/atom/ns#' term='programming'/><title type='text'>Lessons from Laundry</title><content type='html'>&lt;p&gt;&lt;i&gt;Several years ago, I was advising a student on some code he had written for a data structures class. This code performed a set of actions on a temporary counter, and he was resetting the counter to zero after the last action so it would be ready for the next cycle of actions. I suggested setting the counter to zero just before the first action instead of just after the last action. He asked why, and this was my explanation.&lt;/i&gt;&lt;/p&gt;&lt;p&gt;&lt;i&gt;This is also an example of what Jeanette Wing and others call &lt;a href="http://www.cs.cmu.edu/~CompThink/"&gt;computational thinking&lt;/a&gt;.&lt;/i&gt; &lt;/p&gt;&lt;p&gt;You know when you're doing laundry and you have to clean the lint out of the lint trap?  Of course, this is not mandatory&amp;#8212;the dryer will still work if you don't clean out the lint, but it'll work more efficiently if you do.&lt;/p&gt;&lt;p&gt;Now, you have two basic choices as to when to clean out the lint.  You can clean it out when you remove clothes from the dryer, or you can clean it out when you put clothes into the dryer.  Either protocol will work fine as long as everybody in the house is following the same protocol.&lt;/p&gt;&lt;p&gt;But suppose you have two people in the house following opposite protocols.  Let's say that you follow the clean-after protocol and your housemate follows the clean-before protocol.  If you do a load of laundry and clean out the lint trap when you're done, and then your housemate does a load of laundry, then the worst that will happen is that the lint trap will already be clean when your housemate goes to clean it.&lt;/p&gt;&lt;p&gt;On the other hand, if your housemate does a load of laundry and cleans out the lint trap at the beginning, and then you do a load of laundry, now you have a problem.  When you go to clean out the lint when you're done, you'll find it extra full.  You might even need to run the dryer a second time because your clothes didn't get completely dry.&lt;/p&gt;&lt;p&gt;The point is that some protocols, such as the clean-after protocol, only work if everybody follows the same protocol.  Other protocols, such as the clean-before protocol, are more robust; they work fine&amp;#8212;at least for you&amp;#8212;even if some people follow the other protocol.  If you can't guarantee that others will follow (or even remember!) a particular protocol, then you're better off choosing the robust protocol.&lt;/p&gt;&lt;p&gt;Here's a similar example.  In college, I used to play a lot of bridge in the dorm lounge.  In the hall right outside the lounge, there was a small bathroom.  Now, there were two protocols concerning this bathroom.  In the first protocol, you lock the door when using the bathroom; in the second protocol, you knock before entering.  Somebody following the locked-door protocol may or may not knock, while somebody following the knocking protocol may or may not lock the door.&lt;/p&gt;&lt;p&gt;As long as everybody in the dorm follows the same protocol, there's no problem.  But if different people follow different protocols, there can be tragic (or at least embarrassing) consequences!&lt;/p&gt;&lt;p&gt;In this example, perhaps the best course of action is to follow &lt;i&gt;both&lt;/i&gt; protocols: lock the door &lt;i&gt;and&lt;/i&gt; knock.  The same is possible in many other situations where you want to be extra careful: clean the lint after drying but also check it again just before drying, initialize the counter just before the first action but also reset it to zero just after the last action, wear both a belt &lt;i&gt;and&lt;/i&gt; suspenders.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-8142011129191395151?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/8142011129191395151/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=8142011129191395151' title='2 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8142011129191395151'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/8142011129191395151'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/01/lessons-from-laundry.html' title='Lessons from Laundry'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>2</thr:total></entry><entry><id>tag:blogger.com,1999:blog-2564777502681463717.post-1847924758832860357</id><published>2008-01-18T15:15:00.000-05:00</published><updated>2008-01-20T13:44:17.785-05:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='teaching'/><title type='text'>Why I Don't Use PowerPoint For Teaching</title><content type='html'>&lt;p&gt;&lt;em&gt;This essay was originally written for a talk I was giving to brand new faculty members. I'll let it stand as an introduction to one of my passions—teaching. I'll introduce other passions in the coming weeks. Welcome to my blog!&lt;/em&gt;
&lt;/p&gt;&lt;p&gt;Ok, I’m a freak. I admit it. I don’t use PowerPoint for teaching. Well, hardly ever. Once or twice a semester. Around my institution—and across the country—that puts me in the tiny minority. I know this because my students find it unusual enough to comment on. (&lt;em&gt;Update: Since I wrote this, PowerPoint use in the classroom appears to be on the decline, at least at my institution. Hooray!)&lt;/em&gt;
&lt;/p&gt;&lt;p&gt;Why do I take this heretical position? Part of it is that PowerPoint doesn’t mesh well with my personal teaching style. But mostly it’s because PowerPoint is just too hard for me. Oh, not making slides. That part’s easy. I mean that creating a PowerPoint presentation that &lt;i&gt;effectively&lt;/i&gt; supports my goals in the classroom is too hard. It’s way too much work. Some people can—I tip my hat to them—but me? I’m just not good enough to do that. &lt;/p&gt;&lt;p&gt;I’m sure you’ve seen through my little rhetorical device to the arrogance that lies beneath, the arrogance that says “I think I’m pretty good, so if I’m not good enough, then I think most other people aren’t either”. But what makes using PowerPoint for teaching so hard, when it &lt;i&gt;seems&lt;/i&gt; so seductively easy? &lt;/p&gt;&lt;p&gt;Well, that’s exactly the problem. PowerPoint &lt;i&gt;is&lt;/i&gt; seductively easy. The problem is that PowerPoint makes it easy &lt;i&gt;to do the wrong things&lt;/i&gt;. &lt;/p&gt;&lt;p&gt;Here’s an analogy. If you have taught beginner programming classes, you have seen badly indented code. Why? Because in an editor that does not automatically indent, it is easier to write badly indented code than to indent properly. (At least in the short term. Most students don't believe us when we tell them that indenting their code properly will actually save them time in the long run.)&lt;/p&gt;&lt;p&gt;With PowerPoint, however, the situation is more subtle. That’s where the “seductive” part comes in. With indentation, the student usually knows that he is doing the wrong thing, but does it anyway. With PowerPoint, the instructor probably sincerely believes he is doing the right thing. &lt;i&gt;The road to hell is paved with good intentions…&lt;/i&gt; &lt;/p&gt;&lt;p&gt;Let’s look at five ways that PowerPoint makes it easy to do the wrong thing.&lt;/p&gt;
&lt;h4&gt;Presentations&lt;/h4&gt;&lt;p&gt;The original name of PowerPoint was &lt;i&gt;Presenter&lt;/i&gt; and that’s exactly what PowerPoint was designed for—presentations. Think about what that implies. One person (the presenter) is presenting information to other people (the audience). The flow of information is one way, from the presenter to the audience. Because the flow of information is one way, the presenter can and does script out the entire presentation ahead of time, much like a movie or a novel. Like those forms, a PowerPoint presentation is highly linear. It is meant to be experienced in a particular order. Deviating from the expected order is possible, but awkward. This model has little room for interactivity, except perhaps a single slide at the end labeled “Questions?”. &lt;/p&gt;&lt;p&gt;There are contexts where this linear model may be appropriate. You’ve probably seen presentations like this at business meetings or at research conferences. But the purpose of those presentations is not &lt;i&gt;teaching&lt;/i&gt;. The goal may be to inform, to persuade, maybe even to train, but the goal is not to educate. What’s the difference? In a presentation, you are trying to make the audience think &lt;i&gt;your&lt;/i&gt; thoughts, but in education, you are trying to teach students &lt;i&gt;to think for themselves&lt;/i&gt;. In terms of the well-known fishing analogy, it’s the difference between giving somebody a fish and teaching them how to fish. &lt;/p&gt;&lt;p&gt;To teach students to think for themselves, you must give them plenty of opportunities to think for themselves and then respond to those thoughts (or allow others to respond). But this breaks the model of information flowing in one direction in a linear order. Instead you now have information flowing in both directions—a feedback loop—and the order of information can and will change based on that feedback. Good teaching is highly interactive. A good teacher is highly &lt;i&gt;adaptive&lt;/i&gt;, and can change the entire direction of a lesson midstream based on student input. But, if you’re using PowerPoint, how do you change direction midstream? It’s hard to tell students “Just wait a few minutes while I edit these slides!” &lt;/p&gt;&lt;p&gt;You may remember the “Choose Your Own Adventure” books that were popular twenty or thirty years ago. You would read a page, and at the end of the page would be some choices. “If you pay the troll and cross the bridge, go to page 117. If you try to cross without paying, go to page 98. If you attack the troll, go to page 140.” These books were an attempt to shoehorn an interactive form into an inherently linear medium. It was an uncomfortable fit, and these books were soon replaced by computer programs that hid the linearity. It is certainly possible to design a PowerPoint presentation that supports interaction in this fashion, but, like the Choose Your Own Adventure books, it is always an uncomfortable fit. &lt;/p&gt;&lt;p&gt;So this is the first way that PowerPoint makes it easy to do the wrong thing. PowerPoint makes it easy to create a linear presentation, but hard to create an interactive &lt;i&gt;lesson&lt;/i&gt;.
&lt;/p&gt;
&lt;h4&gt;“It’s only wafer thin”&lt;/h4&gt;&lt;p&gt;There is a scene in Monty Python’s &lt;i&gt;The Meaning of Life&lt;/i&gt; in which, at the end of a ridiculously large meal, the maitre d’ offers a diner a mint. At first, the man refuses, but the maitre d’ talks him into it, saying “It’s only wafer thin” and later “Oh, sir, just—just one.” The man eats the mint and literally explodes. (There’s also a brilliant send up of this scene in the comic strip Foxtrot, where a girl wakes up with a swollen head after cramming for finals, and her brother taunts her, saying “It’s only a wafer-thin math formula!”)&lt;/p&gt;&lt;p&gt;This is the second way that PowerPoint makes it easy to do the wrong thing. There’s always the temptation to add just one more word, just one more bullet, just one more slide. It’s so easy to do, and, after all, wouldn’t the students be better off with more information, with more complete slides? &lt;/p&gt;&lt;p&gt;Well…no. Students have a limited capacity to absorb information from slides. Exceed this capacity, and they not only fail to absorb the excess, they also fail to absorb or retain what came before. This can happen either when a single slide contains too much information or when the presentation as a whole has too many slides. &lt;/p&gt;&lt;p&gt;Think of that limited capacity in terms of juggling. Most people can learn to juggle three balls with a little practice, but juggling four is much more difficult. So there you are, happily juggling three balls, when somebody tosses you another ball. What happens? Do you just drop the new ball and continue juggling the three you already have? No. What really happens is you drop all four balls. &lt;/p&gt;&lt;p&gt;Teachers often prepare extra slides “just in case there’s extra time” or “just in case somebody asks”. After all, as discussed above, you want to be prepared to respond to student questions. That’s fine, as long as you are strong-willed enough to resist the temptation to show the extra slides. But, all too often, once you’ve invested the time and effort to create a slide you’re proud of, the psychological pressure to show that slide is irresistable. &lt;/p&gt;&lt;p&gt;Extra slides also cause awkward navigation issues. Where do you put the extra slide? Do you put it in the middle of the presentation, right where it might be needed? If so and it turns out not to be needed, then you have to hurriedly skip over the slide when it comes up, which never looks good. Or do you put it out of the way at the end of the presentation? But then, if it is needed, you have to skip through possibly dozens of slides to reach the extra one, and then go backwards through the same slides to get back to where you were. There are technical ways around these problems, but hardly anybody uses them. &lt;/p&gt;
&lt;h4&gt;He who controls the clicker, rules the world&lt;/h4&gt;&lt;p&gt;Have you ever fought with a sibling or spouse or significant other over who gets to hold the TV remote control? This can be particularly contentious when you intend to channel surf, but the issue arises even if all you intend to do is watch a DVD. Why bother to fight over the remote in that situation? Because the person who holds the remote has enormous power. Another viewer with even the smallest request must approach as a humble supplicant—“please hit pause”, “please turn the volume up”, “hold on, I missed that, can you please go back a little bit?” &lt;/p&gt;&lt;p&gt;Teaching from PowerPoint slides is like holding the TV remote control (and, in fact, you may be literally holding a projector remote control). The teacher decides what slides to show and what to say about each, when to advance and when to go back, when to turn off the screen and when to turn it on. The teacher is in complete control. This is the epitome of &lt;i&gt;teacher-centered learning&lt;/i&gt;, and is the third way in which PowerPoint makes it easy to do the wrong thing. &lt;/p&gt;&lt;p&gt;Especially to new teachers, being in complete control may sound like a good thing. The teacher's the one who knows what he's doing—of course the teacher should be in control! So then why does our dean's vision explicitly state that “Teaching is &lt;i&gt;student centered&lt;/i&gt; and encourages active learning”?&lt;/p&gt;&lt;p&gt;Sure, the phrase &lt;i&gt;student centered&lt;/i&gt; has been overused to the point of becoming educational gobbledygook, but there is an important idea there. The ultimate goal in any classroom is not for the instructor to teach, but for the student to learn. So shouldn’t attention be on the student learning? In a PowerPoint presentation, the attention is mostly on the teacher—the instructor is (mostly) concentrating on his own performance and the students are (hopefully) paying attention to that performance. Here’s a simple rule of thumb for you: If you’re not paying &lt;i&gt;more&lt;/i&gt; attention to the students than they are paying to you, then your class is not student centered.&lt;/p&gt;&lt;p&gt;I always allow students to bring a single page of notes to exams. I encourage them to prepare the notes themselves, because the biggest benefit of the notes lies not in having the notes on the exam but rather in &lt;i&gt;the cognitive act of organizing the information&lt;/i&gt;. Paradoxically, students who prepare their own notes often find that they never once refer to them during the exam, because the act of preparation was enough to get the information into their heads. On the other hand, students who use other people’s notes often find them useless on an exam because &lt;i&gt;they don’t really understand how the information is organized&lt;/i&gt;. &lt;/p&gt;&lt;p&gt;This highlights the flaw in teacher-centered instruction, especially instruction based around PowerPoint. In creating the slides, the teacher is imposing his own organization of the information on the students, when he should be helping the students to organize the information for themselves. &lt;/p&gt;
&lt;h4&gt;Active learning&lt;/h4&gt;&lt;p&gt;My friend Susan doesn’t like to listen to books on tape in the car, because inevitably she will zone out for a while and have to back up the tape. In a PowerPoint slide show, students also will inevitably zone out for a slide or two (or six). But when (if!) their attention wanders back to you, they probably will not ask you to back up the presentation a few slides. Not only will they have lost any chance of learning the content of the slides they missed, but now they probably will not have the context to be able to learn anything from the upcoming slides. And so the lost students will happily return to daydreaming. This is one danger of passive learning and why lectures are so often condemned. In a classroom where students are allowed to be passive observers, they need only keep reasonably attentive expressions on their faces and the instructor will never realize that no learning is taking place (or at least not until the moment has long passed). &lt;/p&gt;&lt;p&gt;This is the fourth way that PowerPoint makes it easy to do the wrong thing. The more you rely on slides, the more passive the students become. &lt;/p&gt;&lt;p&gt;Contrast a lesson where students are passively observing a PowerPoint presentation with a lesson where students are actively engaged in solving a problem. How easy is it to zone out when you are sitting at a desk looking at a screen full of text as opposed to when you are, say, trying to design a solution on a whiteboard? Now the intructor has a better chance of noticing that a student has failed to learn some important point in time to do something about it. Even better, the student has a better chance of &lt;i&gt;remembering&lt;/i&gt; the important points of the lesson because memory formation and retrieval depend at least in part on how many different parts of the brain are active. When a student is thinking, writing, drawing, explaining, and building, more parts of the brain are involved than when he is merely watching and listening. &lt;/p&gt;&lt;p&gt;Although I know of no studies that measure audience brain activity during a PowerPoint presentation, I wouldn’t be surprised if it resembled the relatively flat EEGs found when people watch TV.&lt;/p&gt;
&lt;h4&gt;“It’s a floor wax &lt;i&gt;and&lt;/i&gt; a dessert topping”&lt;/h4&gt;&lt;p&gt;Although I almost never use slides in the classroom, I do use them for giving research talks. I am often approached and asked “I missed your talk. Can I get a copy of your slides?” The other person is usually shocked—and initially annoyed—when I say no. But they usually understand when I explain “I wrote the slides to accompany my talk. They wouldn’t make any sense without my words to go along with them. You’re better off looking at my paper, which was intended to be read on its own.” &lt;/p&gt;&lt;p&gt;A trap that instructors often fall into is putting their PowerPoint slides on the web. They feel virtuous in doing so, patting themselves on the back for helping out students who missed class and for giving students something to review later. This is the fifth way that PowerPoint makes it easy to do the wrong thing. &lt;/p&gt;&lt;p&gt;But how can it possibly be the wrong thing to give students your slides? Because slides that were designed for use in the classroom probably will not work well when viewed from a student's room, and slides that were designed to be viewed outside of class almost certainly will not work well in the classroom. Like the combination floor wax/dessert topping from the classic Saturday Night Live skit, it is nearly impossible to serve both purposes well—you can’t serve two masters. Chances are high that if you try to serve both purposes well, you’ll fail at both. &lt;/p&gt;&lt;p&gt;So perhaps you decide that you’re going to focus on making slides that work well in the classroom, and accept that maybe they won’t work so well from the student's room. Wouldn’t it still be better to give students the slides? Wouldn’t ineffective slides be better than nothing? Not necessarily. Not if the main outcome is to give students a false sense of security and to prevent them from seeking more effective means of learning. A student faced with the choice of reviewing bad slides, talking to a buddy about their notes, unsealing the shrinkwrap on the textbook, or coming in to see the teacher or TA will all too often choose the slides because they seem the easiest. &lt;/p&gt;&lt;p&gt;Going the other direction and deciding to focus on making slides that stand alone when read from the student's room is even worse. That way lies the kinds of overfull slides that leave students muttering “Death by PowerPoint”. Furthermore, students actively resent sitting through a 50 minute lecture when they feel they could have read through the slides in 10 minutes and gotten just as much out of it—especially when that impression is accurate! &lt;/p&gt;&lt;p&gt;In fact, the situation is even worse than I’ve described because instructors often try to create slides that serve &lt;i&gt;more&lt;/i&gt; than two purposes: &lt;/p&gt;&lt;ul&gt;&lt;li&gt;visual aids for during the lesson &lt;li&gt;make-up material for students that missed the lesson &lt;li&gt;review for students that were present at the lesson &lt;li&gt;handouts for students during the lesson &lt;li&gt;read-ahead before the lesson &lt;li&gt;notes to the instructors themselves&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;I don’t care if you are Socrates, Halliday&amp;amp;Resnick, and Edward bloody Tufte all rolled into one. Try to do all this with one set of slides and you &lt;i&gt;will&lt;/i&gt; fail. Decide which purpose you are trying to serve and serve it well.&lt;/p&gt;
&lt;h4&gt;Searching for the harder right&lt;/h4&gt;&lt;div style="PADDING-RIGHT: 0.5ex; PADDING-LEFT: 0.5ex; FLOAT: right; PADDING-BOTTOM: 0.5ex; FONT: bold 1em sans-serif; WIDTH: 40%; PADDING-TOP: 0ex"&gt;Make us to choose the harder right instead of the easier wrong.
&lt;div style="TEXT-ALIGN: right"&gt;– USMA Cadet Prayer&lt;/div&gt;&lt;/div&gt;&lt;p&gt;I've shown five ways in which PowerPoint encourages you, subtly or not so subtly, to choose the easier wrong. But what then is the harder right? Sorry, I can't tell you. Good teaching is hard, and part of what makes it hard is that it is both highly personal and highly context dependent. &lt;i&gt;My&lt;/i&gt; solution wouldn't necessarily be right for &lt;i&gt;you&lt;/i&gt;. &lt;/p&gt;&lt;p&gt;I admit that's a cop out, but it's also true.

For some of you, PowerPoint itself might be the harder right. If you use it carefully and in moderation, with an eye out for the kinds of traps described above, you can probably do fine. But it sure is a lot more work that way, isn't it?&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/2564777502681463717-1847924758832860357?l=okasaki.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://okasaki.blogspot.com/feeds/1847924758832860357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='http://www.blogger.com/comment.g?blogID=2564777502681463717&amp;postID=1847924758832860357' title='12 Comments'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1847924758832860357'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/2564777502681463717/posts/default/1847924758832860357'/><link rel='alternate' type='text/html' href='http://okasaki.blogspot.com/2008/01/why-i-dont-use-powerpoint-for-teaching.html' title='Why I Don&apos;t Use PowerPoint For Teaching'/><author><name>Chris Okasaki</name><uri>http://www.blogger.com/profile/18247315355264748920</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='http://img2.blogblog.com/img/b16-rounded.gif'/></author><thr:total>12</thr:total></entry></feed>
