言語を増やしたかったのと、そういう関数に名前を付けたかったのとで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
let mapBetween f sq = Seq.windowed 2 sq |> Seq.map (Seq.reduce f)