Section 10.3.  Perl Golf

Table of Contents

10.3. Perl Golf

The golfers are another example of the funny side of Perl; these are players of the game invented by Uri Guttman and played out on the golf@perl.org (Perl Golfers) mailing list and far too many other places, such as in front of those asking for help with relatively trivial problems on comp.lang.perl.misc. The goal of this particular sport is to solve a programming problem in as few characters as possible.

For instance, consider generating the Fibonnacci series (1, 1, 2, 3, 5, 8, etc.). One might start with the following uninspired program:

    perl -e '$a=$b=1; while (1) {$c= $a+$b; print $c,"\n"; $a=$b; $b=$c; }'

This weighs in at an abysmal 61 characters, or strokes. We can immediately improve on this by removing extraneous whitespace and making use of the -l option to print newlines after every print statement:

    perl -le '$a=$b=1;while(1){$c=$a+$b;print$c;$a=$b;$b=$c;}'

This gives us a slightly more respectable 48 (the -l counts as a stroke), but that's still way over par. Let's notice that the second "1" constant isn't doing anything, the assignment followed by print will always yield a true value, so we can use that instead:

     perl -le '$a=$b=1;while(print$c=$a+$b){$a=$b;$b=$c;}'

We're now down to 43, and we can get rid of the initial $a= and the last semicolon for another three strokes. Maybe you feel we would be better off without an intermediate variable:

    perl -le '$b=1;while(print$a+$b){($a,$b)=($b,$a+$b)}'

but this again yields 43 strokes. A new train of thought is required.

So far we've been computing the n'th term and printing it, then shuffling our variables around so we stored the n'th and n-1'th. But what we can do is carry about the n'th and n-1'th terms and increment each by the other: f(n) + f(n-1) yields f(n+1), and f(n+1) + f(n) yields f(n+2). This time we generate two terms inside our loop:

    perl -le '$b=1;while(1){$a+=$b;print$a;$b+=$a;print$b}'

We're now back up to 45 strokes, but this formulation leads naturally to:

    perl -le '$b=1;while(1){print$a+=$b;print$b+=$a}'

and thence to the beautifully symmetric:

    perl -le '$b=1;print$a+=$b while print$b+=$a'

This is 35 strokes, not bad; I dare say it can be improved upon, but aesthetics forces me to stop here. Ooh, no, one more thing:

    perl -le 'print$a+=$b while print$b+=$a||1'

33 strokes in all. Oh, and we can shave a character by using a special variable instead of $b, because then we won't need the space after while:

    perl -le 'print$a+=$}while print$}+=$a||1'

32 strokes. Beat that if you can!

All right, I admit it; it's addictive.

    Table of Contents
    © 2000- NIV