This file was automatically generated from http://svn.pugscode.org/pugs/docs/other/primes_rambling.pod on Wed Jun 6 22:16:47 2007 GMT, revision 16639.
Ok, I finally re-installed Perl6 and, given it's august, I'll probably try and use it a bit. So I came back to the time when I was learning to program in Pascal, trying to make stupid programs related to prime numbers, and tried to do something similar.
The first issue to solve is to get some input from the user, whatever I want to do with it. A program controlled if some number n was prime, another calculated the n-th prime number, another one the first prime number above a given number n... in any case, we need n.
In Perl 5, I'd resort to either the command line, or the standard input, with something along these lines:
my $n = shift || <>;
In Perl 6 it doesn't seem so straightforward:
#!/home/poletti/bin/pugs # vim: filetype=perl : use v6; my $n = shift || <>; say "you requested $n";
(Yes, I use vim :) A nice thing in Perl 6 is that you can say things
instead of simply printing them - this automatically adds a \n
at the end of the "sentence".
Time to execute:
poletti@PolettiX:~/sviluppo/perl/perl6$ pugs primes.pugs
***
unexpected "|"
expecting term
at primes.pugs line 5, column 15
Ouch! I got hit by the shift! Time to grep something inside the examples
directory, where I find the matrix.p[56] example! Ok, before I go on
I must confess one thing - instead of
my $n = shift || <>;
I had originally written:
my $n = shift; $n = <> unless defined $n;
which is a little cleaner (think of the case of '0' being input) but much
much uglier :) I found the one-line idiom in matrix.p5, anyway.
Ok, so matrix.p6 basically translates the one-line into:
my $n = @*ARGS[0] || =<>;
Ugh! Apart from the fact that this probably won't shift anything, it's
much more counter-intuitive typing! Wait a minute... this works as well:
my $n = @ARGS[0] || =<>;
Now is a bit more readable IMHO, even if there is the obvious mentality
shift in the sigil and, of course, the change in the name (in Perl 5 this
would be spelt $ARGV[0]). But why do
they both work?!? What's this asterisk for? An hint from IRC points me
towards the Synopses, and in particular in
Synopsis 2: Bits and Pieces I find that Perl 6 does not simply have
sigils, but has twigils as well! The asterisk indicates that the
ARGS variable to be used is one on the global scope, so here it is! The
translator has been semantically more correct (for this aspect), but
we're still missing the shift:
my $n = @*ARGS.shift || =<>;
which works as well, and does exactly what I wrote in Perl 5. I think I'll
miss the "defaulting" feature of shift (but only for a bit).
Now the part after the "||"... why the equal sign? I already know a little
bit: the <whatever you put here> syntax is now used as a shortcut
for the good ol' qw operator, so:
my $m = <>;
would simply put the empty string into $m! Again in Synopsis 2 I learn
that the input is now handled with a single equal sign, like in:
for =$handle { ... }
but why I need the <> is now a mistery... What if it really represents
the empty string, as above? Let's try:
#!/home/poletti/bin/pugs # vim: filetype=perl : use v6; my $n = @*ARGS.shift || =''; say "you requested $n";
no way:
poletti@PolettiX:~/sviluppo/perl/perl6$ pugs primes.pugs
*** : openFile: does not exist (No such file or directory)
at primes.pugs line 5, column 1-28
But hey! This is no fair substitution at all! Let's try the qw operator
instead:
#!/home/poletti/bin/pugs
# vim: filetype=perl :
use v6;
my $n = @*ARGS.shift || =qw{};
say "you requested $n";
Now it works! Only... why? The docs report that the equal sign in this case acts as some kind of "activator" for what follows, and it probably expects to receive an empty list to think "let's read something". As a matter of fact, this works as well:
#!/home/poletti/bin/pugs # vim: filetype=perl : use v6; my $n = @*ARGS.shift || =() ; say "you requested $n";
The bottom line is probably that there is a little "visual"
shift from <> to
=<>, so it's probably better to stick to the original translation
in this case.
The basic function in all my Pascal trials was, of course, the one that checked from number primeness. And no, I am not going to provide some clever implementation.
Let's start with a stub function and a simple message output:
#!/home/poletti/bin/pugs
# vim: filetype=perl :
use v6;
my $n = @*ARGS.shift || =<> ;
say "$n is ", (is_prime($n) ? '' : 'NOT '), 'prime';
sub is_prime { return 1; }
Wow, it blows! Here's the error I got:
poletti@PolettiX:~/sviluppo/perl/perl6$ pugs primes.pugs 5
***
unexpected "?"
expecting comment, operator or ")"
at primes.pugs line 7, column 29
But I know why: the good ol' ternary ? : has now become ?? ::, so
the change is straighforward:
#!/home/poletti/bin/pugs
# vim: filetype=perl :
use v6;
my $n = @*ARGS.shift || =<> ;
say "$n is ", (is_prime($n) ?? '' :: 'NOT '), 'prime';
sub is_prime { return 1; }
What the heck! It blows again!
poletti@PolettiX:~/sviluppo/perl/perl6$ pugs primes.pugs 5
***
unexpected ":"
expecting comment, operator or "!!"
at primes.pugs line 7, column 35
This should teach me to read the documentation: the ternary (operator?
test?) has now become ?? !!, with the exclamation point instead of the
colon! Hummm, that beatiful "Periodic Table of Perl 6 Operators" needs
some updating, let's see... ok now this works:
#!/home/poletti/bin/pugs
# vim: filetype=perl :
use v6;
my $n = @*ARGS.shift || =<> ;
say "$n is ", (is_prime($n) ?? '' !! 'NOT '), 'prime';
sub is_prime { return 1; }
Incidentally, it's good to see that the good ol' syntax for subroutine declaration and definition is still alive! Let's write the sub, now, starting with the first bits:
sub is_prime {
my $n = shift;
return 0 if $n <= 1;
return 1 if $n <= 3;
return 1;
}
Ouch! I got biten by the lonely shift again! No defaults, so I promptly
correct to:
sub is_prime {
my $n = shift @_; # Using shift as a function here, not as method.
# Just to try it out.
return 0 if $n <= 1;
return 1 if $n <= 3;
return 1;
}
Good to see the postfix if still working. But in Perl6 there's more
for this sub parameters stuff, as audreyt suggested in IRC:
sub is_prime ($n) { # Parameters! Arguments! No more "prototypes"!
return 0 if $n <= 1;
return 1 if $n <= 3;
return 1;
}
It's true, subroutine parameters are fully supported now, a big step from the prototypes available in Perl5.
On with the "hard" part, now; again, I'll try to go Perl 5 to start:
sub is_prime ($n) {
return 0 if $n <= 1;
return 1 if $n <= 3;
for my $factor (2 .. sqrt($n)) {
return 0 unless $n % $factor;
}
return 1;
}
No way. Iteration is done differently, but discovering why reveals a lot of interesting things... First of all, I wasn't so distant from something working; had I used the default variable, it would have worked! So:
sub is_prime ($n) {
return 0 if $n <= 1;
return 1 if $n <= 3;
for (2 .. sqrt($n)) {
return 0 unless $n % $_;
}
return 1;
}
works! But Synopsis 4: Blocks and Statements teaches more: the assignment
is visually more sweet:
sub is_prime ($n) {
return 0 if $n <= 1;
return 1 if $n <= 3;
for (2 .. sqrt($n)) -> $factor {
return 0 unless $n % $factor;
}
return 1;
}
The final thing that I read from the docs is controversial in my mind: does it clarify something that had remained obscure, or just adds fog in my brain? It turns out that instead of writing:
while (<>) { ... } # Perl 5
you'd better write
for =<> { ... } # Perl 6
Wow, that =<> again! But this is claimed to be short for
for =$*ARGS { ... }
Oh, my! This is where I appreciate my 33 years: I can stop it here without feeling (too) guilty ;)
Well, Perl 6 seems a lot cool, I've no doubt about this. The "old" code
won't work seamlessly, at least not in a use v6; condition, but this was
expected given the big changes happening. There are probably things I'll
miss, like the defaulting feature of shift, but all in all it's not that
loss.
The documentation is sort-of complete - after all we have Pugs - but rather difficult to navigate and not always "explicit". But I surely didn't expect anything more! Some aspects are still obscure... but I'll leave them for the next time!
Last, but not least, here's the final script:
#!/home/poletti/bin/pugs
# vim: filetype=perl :
use v6;
my $n = @*ARGS.shift || =<> ;
say "$n is ", (is_prime($n) ?? '' !! 'NOT '), 'prime';
sub is_prime ($n) {
return 0 if $n <= 1;
return 1 if $n <= 3;
for (2 .. sqrt($n)) -> $factor {
return 0 unless $n % $factor;
}
return 1;
}