言語を増やしたかったのと、そういう関数に名前を付けたかったのとで1 entry割くことにしました。

等差数列 - タイトル
配列の隣接する2項にそれぞれ演算を施した配列を得たい。つまり、
f (+) [1,2,3,4,5] = [3,5,7,9]
のような f が欲しい。

名前

もちろん等差数列を作るのにもこの関数は使えるのですが、この一般的に使える関数に使う名前としてはあまりに局所的。というわけで mapBetween としてみました。使いどころはかなり多そうです。各言語に標準装備されていないのがちょっと不思議なほど。

JavaScriptによる実装

Array.prototype.mapで滅多に使われない第二引数を使ってみました。

Array.prototype.mapBetween = function(callback, thisArg) {
    return this.slice(0, -1).map(function(v, i) {
        return callback.call(thisArg, v, this[i]);
    }, this.slice(1));
};

Perlによる実装

map BLOCK LISTのBLOCKの呼び出しではスタックを積まない、つまり@_がそのままである点に気が付くと以下のように書けます。

use 5.012;

sub mapBetween(&@) {
    map { $_[0]->( $_[$_], $_[ $_ + 1 ] ) } 1 .. @_ - 2;
}

say '# ', join ",", mapBetween { $_[1] - $_[0] } ();
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1, 4);
say '# ', join ",", mapBetween { $_[1] - $_[0] } (0, 1, 4, 9);

ただしCORE::sort()List::Utils()などで見られる、引数の代わりに$a$bを使う記法にも対応させようとすると少し工夫が必要となります。こんなところでしょうか。

use 5.012;

sub mapBetween(&@) {
    my $pkg = caller();
    no strict 'refs';
    map {
        local ( ${ $pkg . '::a' }, ${ $pkg . '::b' } ) =
          ( $_[$_], $_[ $_ + 1 ] );
        $_[0]->( $a, $b )
    } 1 .. @_ - 2;
}

{
    our ( $a, $b ) = ( 'a', 'b' );
    say '# ', join ",", mapBetween { $b - $a } ();
    say '# ', join ",", mapBetween { $b - $a } (0);
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1 );
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1, 4 );
    say '# ', join ",", mapBetween { $b - $a } ( 0, 1, 4, 9 );
    say $a, $b;
}
{
    package NotMain;
    our ( $a, $b ) = ( 'A', 'B' );
    say '# ', join ",", main::mapBetween { $b - $a } ();
    say '# ', join ",", main::mapBetween { $b - $a } (0);
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1 );
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1, 4 );
    say '# ', join ",", main::mapBetween { $b - $a } ( 0, 1, 4, 9 );
    say $a, $b;
}

Enjoy!

Dan the Mapper in between