I’ve contrived to do a good bit of $work programming in Perl 6 over the last few weeks, and I’ve been forced to develop a few new (or at least, new to me) idioms in the process. In particular, here’s one I mentioned on #perl6:
sub length(@points) {
[+] (1 ..^ +@points).map({distance(@points[$_], @points[$_ - 1])});
}
Frequently in geometry you have to do something like this, where you have an array of items, and must compare each item in the list to the next. Initially I floundered around with code that looked something like this:
sub length(@points) {
for @points.keys -> $i {
next if $i == 0;
distance(@points[$_], @points[$_ - 1])
}
}
(Yes, that version doesn’t actually sum the distances, but you get the idea.) This is essentially trying to translate C++ idioms to Perl 6. The version at the top of the page is clearly better, and I was pleased with myself for working it out.
That said, it occurs to me that it would probably be better to do something like this:
sub pair-with-next(Iterable $a-iterable) {
my $ai = $a-iterable.iterator;
my $previous = $ai.get;
return if $previous ~~ EMPTY;
gather loop {
my $current = $ai.get;
last if $current ~~ EMPTY;
take $previous;
take $current;
$previous = $current;
}
}
(WARNING: This is completely untested code!) With that defined, you’d just say something like
sub length(@points) {
[+] pair-with-next(@points).map(-> $a, $b {distance($a, $b)});
}
That feels much cleaner to me than the first version, and has the advantage that it can work on iterators as well as Seq/Arrays.
May 1, 2010 at 1:56 am |
My Perl 6 is a little outdated, but couldn’t you just do:
sub length(@points) {
[+] (@points Z @points[1..*]).map: distance(*$_)
}
May 1, 2010 at 2:20 am |
Almost, I don’t think
distance(*$_)will quite do it. But yes, your general point of using Z like that is dead on. That idiom doesn’t work in Rakudo at the moment, so it slipped my mind.