The 2006 Pittsburgh Perl Workshop is a ten-ton can of programming whoop-ass

Posted by Tom Moertel Tue, 12 Sep 2006 21:30:00 GMT

I am on the planning committee for the 2006 Pittsburgh Perl Workshop and serve as the primary point of contact for speakers. That means I get the inside scoop on the talks. And from what I have seen, all I can say is, These talks kick ass. Well, actually I can say one more thing:

If there is any possible way you can manage to get yourself to Pittsburgh, Pennsylvania on Saturday, 23 September 2006, do not wait, do not mull it over, register now for the Pittsburgh Perl Workshop.

If you miss this one, you’ll probably end up weeping in front of your keyboard for a long, long time.

Perl At Work

PPW ’06 has speakers from the worlds of finance, bioinformatics, engineering, politics, health care, insurance, Web-2.0 start-ups, environmental monitoring, and mathematics. And they all have fascinating things to share with you about how they make Perl work for them and about how you can make Perl work for you.

Registration is only $20 – can you imagine that, in an age when programming conferences routinely cost hundreds if not thousands of dollars? – and all of the talks show you how to use Perl to do real work, solve real problems, and make your real life as a programming professional a whole lot saner. Even if you think you don’t care about Perl, you ought to be a part of PPW ’06 just for the rare opportunity to discover something you may have overlooked. (At $20, when are you ever going to get a chance like this again?)

Posted in ,
Tags , , , , , ,
1 comment
no trackbacks
Reddit Delicious

Unofficial answers to FAQs about Giant Eagle's “fuelperks” gas discount

Posted by Tom Moertel Thu, 04 May 2006 02:49:00 GMT

Local supermarket chain Giant Eagle has a brilliant marketing scheme called “fuelperks”: For every 50 dollars you spend on groceries in their stores, you earn a one-time, 10-cent-per-gallon discount at Giant Eagle’s “GetGo” gas stations. The discounts accumulate until you use them (or they expire in three months). If you buy 109 dollars of groceries, for example, you will earn a 20-cent-per-gallon gas discount. (The remaining 9 dollars will carry over to your next grocery purchase.)

What makes the scheme brilliant is that its psychological effect is wildly in excess of the discount’s actual value. Many people will wait in lines to buy gas from GetGo, even though the discount provides no incentive to do so. Further, as gas prices rise, many customers perceive the discount to be all the more valuable, even though it is not.

I thought it would be interesting to scrutinize the discount and answer some common questions about it.

How much is the “fuelperks” discount worth?

The discount is typically equivalent to about 3- to 4-percent cash back on your grocery purchases, depending on the average amount of gas you purchase per fill-up. For example, my mid-size car has a 14-gallon tank, and I always buy a full tank’s worth of gas, so for me the discount is about 2.8 percent:

14 gallons × 0.10 dollars/gallon / 50 dollars = 0.028

If you drive a luxury-barge SUV and can manage to buy a full 30 gallons at each fill up, you will earn the theoretical maximum discount of 6 percent.

How do I get the maximum benefit from the discount?

To get the maximum benefit, follow two simple rules:

  • buy a full tank of gas whenever you use earned discounts at GetGo
  • use your discounts before they expire

Do I lose benefits if I buy gas somewhere else?

No. Even if you buy most of your gas somewhere else, as long as you buy gas from GetGo frequently enough to use your discounts before they expire, you will get the maximum benefit.

When gas prices increase, do I get more benefits?

No. The value of any discounts you have earned depend on the quantity of gas you purchase. The price of gas at the time of purchase has no effect on the discount.

Any other questions?

If you have any questions (or comments), please post a comment.

Posted in ,
no trackbacks
Reddit Delicious

The Supermarket Pricing Kata in Haskell

Posted by Tom Moertel Fri, 28 Apr 2006 20:30:00 GMT

At last night’s meeting of the Pittsburgh Coding Dojo, we worked on the Supermarket Pricing Kata. This particular kata was intended to be food for thought – a “shower kata” – but our goal was to do some coding, so we made the problem more concrete:

  • Come up with a sensible way to represent common supermarket pricing rules such as “buy one, get one free,” “three for a dollar,” ”$0.34 per ounce,” and so on
  • Implement a method to check out a shopping cart full of goods, applying all applicable pricing rules, and computing the total price for the cart’s contents

Most people paired up, but I worked alone because I wasn’t ready to code right away. (Laptop issues.) At the end of the meeting, nobody had a working solution. (I guess it was a shower kata for a reason.) I had a partial solution, but I didn’t like my internal representation of prices because it conflated goods and their pricing rules.

Over lunch today I came up with a more sensible representation and finished off my implementation. Now I’m happy with it.

The code

Here’s my solution. I stripped the comments to emphasize the code itself (a forest and trees thing). If you want to see the comments, see the unstripped source.

{-
   My solution to "The Supermarket Pricing Kata" 
   http://blogs.pragprog.com/cgi-bin/pragdave.cgi/Practices/Kata/KataOne.rdoc

   Tom Moertel <tom@moertel.com>
   2006-04-27
-}

module SupermarketPricing where

import Control.Arrow ((&&&))
import Data.List (groupBy, sort)
import Test.HUnit

type Portion  = Double      
type Count    = Portion     
type Price    = Double      
type Name     = String      

data PricingRule
    = Per Portion Price     
    | For Count Price Price 
  deriving (Eq, Ord, Read, Show)

data Good
    = G { name :: Name, quantity :: !Portion, rule :: PricingRule }
  deriving (Eq, Ord, Read, Show)

per nm y x p  = G nm y (Per x p)     
each nm p     = G nm 1 (For 1 p p)   
for nm n p    = G nm 1 (For n p p)   
bogo          = flip bngo 1          
btgo          = flip bngo 2          
bngo nm n p   = G nm 1 (For n' np p) 
                where (n', np) = (n + 1, p * n)

checkout :: [Good] -> Price
checkout =
    checkoutBy $ sum . map price

subtotal :: [Good] -> [((Portion, Name), Price)]
subtotal =
    checkoutBy $ map ((quantity &&& name) &&& price)

checkoutBy :: ([Good] -> a) -> [Good] -> a
checkoutBy f =
    f . map (foldl1 combine) . groupByName . sort
  where
    groupByName = groupBy (\g1 g2 -> name g1 == name g2)

price :: Good -> Price
price (G nm y (Per x p))    =  y * p / x
price (G nm m (For n p p2)) = (m - r) * p / n + r * p2
  where
    r = fromIntegral $ round m `rem` round n

combine :: Good -> Good -> Good
combine g1@(G nm x rule) g2@(G nm2 x2 rule2)
    | nm /= nm2 || rule /= rule2
    = error $ "can't combine incompatible goods " ++ show [g1, g2]
    | otherwise
    = G nm (x + x2) rule

Read on for an explanation of the code and my unit tests.

Read more...

Posted in , ,
Tags , , , , ,
no comments
no trackbacks
Reddit Delicious

Perl and Pittsburgh: fun stuff coming your way!

Posted by Tom Moertel Wed, 12 Apr 2006 16:29:00 GMT

If you live anywhere near Pittsburgh and are interested in Perl, have I got a couple of announcements for you:

First, the ever-fascinating Mark Jason Dominus is speaking tonight (2006-04-12, now passed) on Improving Your Perl Code at the regular meeting of the Pittsburgh Perl Mongers. If you are interested in Perl, be there. (You don’t need to be a Perl Monger to attend.) Mark is a great speaker and wrote one of my favorite Perl books, Higher Order Perl, which puts the fun in functional programming.

Second, The Pittsburgh Perl Workshop is on. Put a big circle around this date on your calendar: Saturday, 23 September 2006. It’s a full day of sleeves-rolled-up Perl fun, all focused on the sweat-inducing theme of Perl At Work. To top it off, the Workshop is dirt cheap, especially if you get the 50-percent “Early Bird” discount. (Hint: register now.)

It’s a fun time for Perl folks in Pittsburgh.

Update: MJD gave his talk, and it rocked. If you missed it, you should find a time machine now and use it to take yourself back to Wednesday evening to hear his talk. Or you could find out when he is speaking in the future and be there. Either way, don’t miss out again.

Posted in ,
no comments
no trackbacks
Reddit Delicious

The Bowling Game Kata in Haskell

Posted by Tom Moertel Wed, 05 Apr 2006 19:18:00 GMT

On the WPLUG mailing list I came across a post about the formation of a Pittsburgh Coding Dojo. The idea is to get a bunch of hackers together and have them work on solving a challenge problem with the goal of sharpening their programming skills and learning from each other.

There was a trial meeting on 31 March that focused on The Bowling Game Kata. The challenge was essentially to write some code that scores a full (ten-frame) game of bowling. A game is represented by a series of “rolls,” each being the number of pins knocked down by a roll of the bowling ball. The scoring function must determine frame boundaries from the sequence of rolls and score all ten frames according to the rules of bowling, i.e., taking into account spares and strikes and the final frame.

The challenge sounded like a fun lunch-break problem, and so I whipped up the following solution in Haskell. (You might find it interesting to compare this solution to the Java-based solutions on the web.)

{-
   My solution to "The Bowling Game Kata" 
   Tom Moertel <tom@moertel.com>
   2006-04-05

   See http://butunclebob.com/ArticleS.UncleBob.TheBowlingGameKata
-}

module Bowling (score) where

import Test.HUnit

-- | Compute the score for the list of rolls 'rs'

score rs = sc 0 1 rs

-- accumulate the score 's' and frame count 'f' while consuming a
-- list of rolls 'rs' one frame at a time

sc s 11 _  = s           -- frame 11 means all done; return score
sc s f rs  = case rs of  -- otherwise, consume the frame & recurse
    10:rs'                -> sc' 3 rs'  -- strike
    x:y:rs' | x + y == 10 -> sc' 3 rs'  -- spare
            | otherwise   -> sc' 2 rs'  -- normal
    _                     -> error "ill-formed sequence of rolls"
  where
    -- accumulate the next 'n' rolls into the score and recurse
    sc' n rs' = sc (s + sum (take n rs)) (f + 1) rs'

Here are my unit tests:

{-
                      *** Unit tests ***

             *Bowling> runTestTT tests
             Cases: 9  Tried: 9  Errors: 0  Failures: 0
-}

tests = test
    [ "gutters"       ~: score  (rep 20  0)          ~?=   0
    , "ones"          ~: score  (rep 20  1)          ~?=  20
    , "fives"         ~: score  (rep 22  5)          ~?= 150
    , "strikes"       ~: score  (rep 12 10)          ~?= 300
    , "1 + gutters"   ~: score  (1 : rep 19 0)       ~?=   1
    , "first spare"   ~: score  (5:5:5 : rep 17 0)   ~?=  20
    , "first strike"  ~: score  (10:5:5 : rep 17 0)  ~?=  30
    , "last spare"    ~: rscore (5:5:5 : rep 18 0)   ~?=  15
    , "last strike"   ~: rscore (5:5:10 : rep 18 0)  ~?=  20
    ]
  where
    rep    = replicate
    rscore = score . reverse  -- reverse list and then score it

If you have a little free time, code up a solution in your favorite language.

Posted in , ,
Tags , ,
4 comments
no trackbacks
Reddit Delicious

Good stuff: Aldo Coffee Company

Posted by Tom Moertel Tue, 31 Jan 2006 02:57:00 GMT

I love espresso. It’s my favorite way to enjoy coffee. Even so, I almost never order espresso in coffee shops because, here in the United States, very few coffee shops have mastered the exacting process by which espresso is made. Dr. Josuma John of the Josuma Coffee Company writes that “more than 95 percent of North American espresso is poorly made, and, in fact, undrinkable.” My experience with Pittsburgh-area coffee shops in the last decade provides no evidence to refute Dr. John’s claim.

If espresso in the United States is so bad, why do Americans drink enough of it to support a Starbucks on every street corner? The reason is that Americans drink espresso almost exclusively in the form of milk-based beverages: cappuccinos, lattes, and mochas. Milk and flavored syrups are the main attractions. Espresso serves only as a coffee-flavored backdrop in which bitterness, a characteristic of poorly made espresso, complements the abundant sweetness of milk laced with sugar syrups. American coffee-shop owners thus have little incentive to offer better espresso to their customers – bad espresso is good enough.

Because of this sad reality, I have developed through hard experience the following reliable guideline for ordering espresso at American coffee shops: Don’t. The one exception I make is for new coffee shops, at which I will try a double espresso, just to see what I get. Almost always, I get a bad espresso, bitter and watery.

And that is what I had expected back in April 2005, when I spotted the brand-new sign for Aldo Coffee Co. in my home town of Mt. Lebanon, Pennsylvania, located in Pittsburgh’s South Hills. I went in, dragging my wife along, and placed my order.

Then something unusual happened. The barista asked me, somewhat hopefully it seemed, if I drank espresso regularly. When I said yes, she seemed pleased. When she followed up by asking me if I read alt.coffee, I was stunned. When I observed that she was timing my shot, my brain actually shut down for a few seconds while it forcibly recalibrated itself to accommodate the seemingly impossible: that I was standing in a coffee shop in my home town, conversing with a barista about alt.coffee, and mere seconds away from receiving what was very likely to be good espresso.

Read more...

Posted in , ,
Tags , , ,
9 comments
1 trackback
Reddit Delicious

Perl Mongers meet at PAPA-8 pinball tournament kickoff!

Posted by Tom Moertel Fri, 12 Aug 2005 16:00:00 GMT

Tonight’s meeting of the Pittsburgh Perl Mongers was held at the World Headquarters of the Professional Amateur Pinball Association to coincide with the PAPA 8 World Pinball Championships.

To say it was a cool meeting doesn’t do it justice. Not only did we hear a fun talk on writing CGI-contained Mason applications by our own Dan Wright, but after the meeting we wandered around and played fabulous, well-maintained vintage pinball machines and fine 1980s-era video games. And we watched the world’s best pinball players compete. And we ate junk food. Yeah!

By all means, do look at the PAPA 8 photos. And if you need the love that only good pinball can provide, experience PAPA 8 for yourself: the tournament runs for the next few days.

A big thanks to PAPA for hosting us!

—Tom

Posted in , ,
no comments
no trackbacks
Reddit Delicious