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.