99 Problems in Perl 6

by Curtis Poe

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.


20 Comments

Stevan Little
2006-12-20 15:06:19
Here is a version in OCaml. Not as short as the Perl 6, but not as long as the others either.

Random.self_init ()


let lotto count range =
let rec accum count acc =
match count with
| 0 -> acc
| _ -> let rec find_unique_element acc =
let x = Random.int range in
if List.mem x acc then find_unique_element acc else x
in accum (count - 1) ((find_unique_element acc)::acc)
in accum count []

NateC
2006-12-20 22:08:38
Don't mean to troll... but as soon as I read the title the following popped in to my head...


Havin' Perl Problems? I feel bad for you son. I got 99 problems but Perl aint one....


Tip of the hat to Jay-Z.

shaurz
2006-12-21 02:41:11
This is how I would solve the problem in C:



void lotto(int m, int *numbers, int n)
{
for (int i = 0; i < m; i++) {
int j = rand() % (n - i) + i;
int tmp = numbers[i];
numbers[i] = numbers[j];
numbers[j] = tmp;
}
}


lotto takes m numbers from an array of n, placed at the start of the array. example usage:



int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};


srand(time(NULL));


for (int test = 0; test < 10; test++) {
lotto(3, numbers, 10);
printf("%d %d %d\n", numbers[0], numbers[1], numbers[2]);
}


There's probably a much nicer way to rewrite the Lisp version.


2006-12-21 02:53:37
Also would like to note, the Perl 6 version is short because the main algorithm is already implemented by the pick method.
Ovid
2006-12-21 03:03:24

shaurz: your code has a bug. Note that the Perl 6 version forbids integers less than 1. If you call lotto with negative numbers, your code breaks. I think it's fair to ask that functionality be equivalent when comparing programming languages :)


2006-12-21 03:15:02
The bug is in the caller ;-)


I guess the point was to show that the problem is trivial, even in a terrible language like C.

Ovid
2006-12-21 03:15:39

Anonymous: that's a fair point, but there are two things to consider. First, Perl 6 is heavily focused on providing built-in solutions to common problems. Thus, .pick might sound like I'm cherry picking (hah!) solutions which look better in Perl 6, but it's common. Want to know if all elements in one list are contained in another?


if ( all(@one_list) == any(@other_list) ) { ... }


Also note that some examples posted don't have the nice "Positive::Int" constraint, thus contain bugs. That's another feature which is harder to concisely duplicate.


Side note: Positive::Int should have been Int::Positive. It's better to go from the general to the specific rather than the other way around.

michele
2006-12-21 03:18:07
import random


def lotto(count, range):
return random.sample(xrange(range), count)


But, as the anonymous commenter said, this is just because the problem has already been solved in the language's standard library.

Ovid
2006-12-21 03:22:20

michele: nothing wrong with the problem being solved by a standard library or a built in feature. Regular expressions are one of the many built-in things which first drove people to Perl. However, what happens to your code if you pass in values less than one? The code's not functionally equivalent.


Of course, I just noticed that my code has the bug that I didn't validate that $count <= $range :)

shaurz
2006-12-21 03:26:13
(sorry, anonymous was me)
Simon
2006-12-21 06:09:33
A bit nicer CL version:

(defun draw-n (n end)
(draw-n* n (make-range 1 end) ()))


(defun draw-n* (n range result)
(if (and (> n 0) range)
(let ((draw (nth (random (list-length range)) range)))
(draw-n* (1- n) (remove draw range) (cons draw result)))
result))


(defun make-range (start end &optional result)
(if (> start end)
result
(make-range (1+ start) end (cons start result))))

michele
2006-12-22 03:12:01
Ovid, I think it does: if either of the values is < 0, or count > range, a ValueError exception will be raised (in the first case, it will have a misleading "sample larger than population" message, though).

2006-12-30 20:19:36
this is a lame example. first off it doesn't work. second off it just relies on a builtin function called "pick". big whoop.
Ed Avis
2007-01-04 02:52:16
It seems to me that the Lisp / Prolog / Haskell versions take pains to be an efficient implementation and not construct a complete list of integers 1 .. $range before picking some. What is the time and space complexity of the different algorithms?
Ovid
2007-01-04 02:55:36

Ed Avis: it's tough for me to answer that, but I do know that Perl 6 also attempts to automatically make lists lazy, so it should be relatively efficient with large lists.

Adam Krolnik
2007-01-10 08:38:24

Too bad most of these problems seem academic exercises.
Compute prime numbers
Compute other math values
Sort lists of lists

Ovid
2007-01-10 08:55:41

Adam, those are problems I encounter all the time while programming. Just the other day I needed to find the least common multiple between two numbers (useful when you need to synchronize timing events, for example), that that requires finding the prime factors of numbers.


Sorting lists of lists is also extremely useful in a number of contexts, including reporting.


Other issues such as filtering and manipulating lists, generating combinations and permutations, working with trees and graphs, etc., are things that I find myself using now and then. While a number of the items are certainly things I haven't used, I certainly have used most of these concepts at one time or another.

rici
2007-01-15 17:13:09
By the way:


lcm(a, b) = a * b / gcd(a, b)
lcm(0, 0) = 0


gcd(a, 0) = a
gcd(a, b) = gcd(b, a mod b)


And, for what it's worth, here's one implemention of the lotto function in Lua, which avoids creating the temporary array, mostly.



do local meta = {__index = function(_, k) return k end}
function lotto(count, range)
local rv = setmetatable({}, meta)
for i = 1, count do
local j = math.random(i, range)
rv[i], rv[j] = rv[j], rv[i]
end
return unpack(rv, 1, count)
end
end
Phil Armstrong
2007-01-18 03:34:19
You're being a little harsh on the other solutions frankly. Line count / character count is not a measure of code quality.


Your argument is in fact: "Look, perl6 has more useful libraries than these other languages!"


Which is a good argument, although a single example is hardly convincing. CPAN might be though! (for those who find it useful)


If you want to make claims about readability, then go and define the pick function in your example & then make the comparison...

Vedananda Gowd.R
2008-03-06 21:43:58
I am totally new to perl package installation. Currently i want to insall Net:Pcap pacakage.
Can any one please let me know the procedure in complete how to do it.
I have tried cpan.org, (Through CPAN i am facing build problem on cygwin) tried ppm (facing problem with proxies).


Please can any one tell me how can i do it.
Thanks in advance,