これはMoritz Lenz氏のWebサイトPerlgeek.deで公開されているブログ記事"Perl 5 to 6" Lesson 24 - The Reduction Meta Operatorの日本語訳です。
原文はCreative Commons Attribution 3.0 Germanyに基づいて公開されています。
本エントリにはCreative Commons Attribution 3.0 Unportedを適用します。
Original text: Copyright© 2008-2010 Moritz Lenz
Japanese translation: Copyright© 2011 SATOH Koichi
NAME
"Perl 5 to 6" Lesson 24 - 縮約メタ演算子
SYNOPSIS
say [+] 1, 2, 3; # 6
say [+] (); # 0
say [~] <a b>; # ab
say [**] 2, 3, 4; # 2417851639229258349412352
[\+] 1, 2, 3, 4 # 1, 3, 6, 10
[\**] 2, 3, 4 # 4, 81, 2417851639229258349412352
if [<=] @list {
say "ascending order";
}
DESCRIPTION
縮約メタ演算子[...]
は結合性のある中置演算子なら何でもリスト演算子に変換します。
これはあたかもリストの各要素間にその中置演算子が置かれたかのように働きます。つまり[op] $i1, $i2, @rest
は$i1 op $i2 op @rest[0] op @rest[1] ...
と書かれたのと同じ結果になります。
これは+
演算子を総和関数に格上げし、~
演算子を(セパレータを空文字列にした)join
にするなど、非常に強力な構文です。
もし関数プログラミングに触れたことがあるなら、(LispやHaskellの)foldl
とfoldr
を多分ご存知でしょう。
これらとは異なり[...]
は元の演算子の結合性に従うので、[/] 1, 2, 3
は(1 / 2) / 3
(左結合)として解釈され、[**] 1, 2, 3
は正しく1 ** (2 ** 3)
(右結合)として扱われます。
他のすべての演算子と同様に空白は使うことができないので、[+]
とは書けますが[ + ]
は駄目です。
比較演算子は連結することができるので、こんな風に書いたりもできます
if [==] @nums { say "all nums in @nums are the same" }
elsif [<] @nums { say "@nums is in strict ascending order" }
elsif [<=] @nums { say "@nums is in ascending order"}
代入演算子でさえ縮約することができます:
my @a = 1..3;
[=] @a, 4; # @a[0] = @a[1] = @a[2] = 4; と同じ
[...]
がいつもスカラを返すことを覚えておいて下さい。なので[,] @list
は[@list]
と同じです。
部分結果の取得
バックスラッシュを使った特別な形式が在ります: [\+]
のような形式です。
これは部分評価結果のリストを返します。つまり[\+] 1..3
は1, 1+2, 1+2+3
というリストを返します。当然これは1, 3, 6
です。
[\~] 'a' .. 'd' # <a ab abc abcd>
右結合の演算子は右から左へ評価していくので、部分結果もその順になります:
[\**] 1..3; # 3, 2**3, 1**(2**3) これは 3, 8, 1
縮約演算子は複数組み合わせることができます:
[~] [\**] 1..3; # "381"
MOTIVATION
プログラマは怠惰であり、2項演算子をリストの全要素に適用するためだけにループなど書きたくないものです。
List.reduce
が同様の機能を持ちますが、これはメタ演算子ほどには簡潔でありません([+] @list
は@list.reduce(&infix:<+>)
になります)し、結合性の面倒を見てくれません。
納得できないなら、この機能を使ってちょっと遊んでみて下さい(Pugsがほとんど実装しています)。本当に楽しいです。
コメント
コメントを投稿