Have you wanted to start playing with Perl 6 but find yourself wondering what to write? I use Pugs, a Perl 6 implementation being written in Haskell and have been tremendously enjoying Perl 6. Like many, I’m impatient, but the work on Perl 6 has been progressing quite well and I’m quite keen to see the alpha. However, if you’re like me, you probably do better with a new language by actually writing something in it. Well, not only do I have something for you to write, you can actually help out the Perl 6 effort!

Recently I stumbled across 99 Problems in Lisp, which was in turn apparently borrowed from 99 Problems in Prolog. I’ve started 99 Problems in Perl 6.

I started out by writing a program which would take the text of the “99 Problems” and split them into separate test files for Perl 6. The first one looks like this:

use v6-alpha;
use Test;
plan 1;

# P01 (*) Find the last box of a list.
# 
# Example:
# * (my-last '(a b c d))
# (D)

is <a b c d>.[-1], 'd', 'Find the last box of a list.';

Each test file contains the entire text of the problem, though some refer you to previous problems. At the current writing, only the first 24 have been “solved” and the rest contain “skip” tests. If you can solve a problem, feel free to send an email to one of the Pugs mailing lists. Commit bits are handed out very liberally. Then you can add the solution and work on other problems.

To give you an example of how some of the languages compare, here’s the “lotto” problem (Draw N different random numbers from the set 1..M) in Lisp:

(defun range (ini fim)
    (if (> ini fim)
        (if (eql ini fim)
            (cons fim nil)
            (cons ini (range (- ini 1) fim)))
        (if (eql ini fim)
            (cons fim nil)
            (cons ini (range (+ ini 1) fim)))))

(defun remove-at (org-list pos &optional (ini 1))
    (if (eql pos ini)
        (cdr org-list)
        (cons (car org-list) (remove-at (cdr org-list) pos (+ ini 1)))))

(defun rnd-select (org-list num &optional (selected 0))
    (if (eql num selected)
        nil
        (let ((rand-pos (+ (random (length org-list)) 1)))
           (cons (element-at org-list rand-pos) (rnd-select (remove-at org-list rand-pos) num (+ selected 1))))))

(defun lotto-select (num-elem max-elem)
    (rnd-select (range 1 max-elem) num-elem))

Wow! That’s hideously verbose and I suspect there’s a better way. Here it is in Prolog:

range(I,I,[I]).
range(I,K,[I|L]) :- I < K, I1 is I + 1, range(I1,K,L).

remove_at(X,[X|Xs],1,Xs).
remove_at(X,[Y|Xs],K,[Y|Ys]) :- K > 1, 
   K1 is K - 1, remove_at(X,Xs,K1,Ys).

rnd_select(_,0,[]).
rnd_select(Xs,N,[X|Zs]) :- N > 0,
    length(Xs,L),
    I is random(L) + 1,
    remove_at(X,Xs,I,Ys),
    N1 is N - 1,
    rnd_select(Ys,N1,Zs).

lotto(N,M,L) :- range(1,M,R), rnd_select(R,N,L).

That’s better, but not much. The Haskell solution isn’t much better:

import System.Random
diff_select :: Int -> Int -> IO [Int]
diff_select n to = diff_select' n [1..to]
 
diff_select' 0 _  = return []
diff_select' _ [] = error "too few elements to choose from"
diff_select' n xs = do r <- randomRIO (0,(length xs)-1)
                       let remaining = take r xs ++ drop (r+1) xs
                       rest <- diff_select' (n-1) remaining
                       return ((xs!!r) : rest)

Here it is in Perl 6:

subset Positive::Int of Int where { $_ > 0 };

sub lotto (Positive::Int $count, Positive::Int $range) returns List {
    return (1 .. $range).pick($count);
}

(The current implementation of Pugs does not yet support a ’subset’, so that’s not yet included in the test problem.)

Needless to say, that’s much easier to read. And look! A better type mechanism :) Part of the reason why that works so well is that Perl 6 is heavily focused on solving problems that programmers really face. Now, rather than testing whether your ‘Int’ is in the allowable range, you can carefully define a special ’subset’ which details what that allowable range is.

So go out there and do my homework! Things which will help:

  • You might want to check the README first.
  • Read the latest Perl 6 documentation,
  • Hang out on #perl6 on irc.freenode.net
  • For Firefox users, create a “perl6doc” keyword search using http://www.google.com/search?q=site%3Aperlcabal.org/%20%s