亀岡的プログラマ日記

京都のベッドタウン、亀岡よりだらだらとお送りいたします。

F# のPipe-forward 演算子(パイプライン演算子)って、C# の拡張メソッドの仕組みと似てるよねー、という雑惑。

2012年5月29日追記:タイトルをtypoっていました。。。

わりとF#面白がって使ってます。まだまだ入門書を必死で社協している最中ですが、楽しいですね、写経。
そんなこんなで、いろいろコード片らしきものは以下に書いています。


なんとなく、今日思考として(そして多分C#er故に)ハマって、かつさっと抜け出せたところをメモがてら記述。

C#での列挙系メソッド、ていうか要するにLinq名前空間に有るメソッド軍っていうのは基本的に、

[列挙型].[メソッド名]

という形で色々メソッドが用意されてます。でもこれ、実体はほとんどが拡張メソッドの集合なんですよね。だから実は、拡張メソッドというシンタックスシュガー抜きにすると

[メソッド名]([列挙型], (次の引数…))

という形で最終的には書かれているはずです。

そいで。

F#の方でも本質的にはおんなじなんですよねー。
例えば、配列型への各メソッドなんて

Array.map [引き当てる関数] [列挙型]
Array.sum [列挙型]

のようになっていて、列挙型の引数が最初にあるかどうか以外は似たようなもんです。
んで、当然のごとくPipe-forward演算子( |> )というシンタックスシュガーを使ってこんなふうに書けます。

[列挙型] |> Array.map [引き当てる関数]

そして、これらのメソッドの多くは列挙型を返すので(map関数なんてまさにそう)、こんなふうに書けるわけです。

[列挙型] |> Array.map[引き当てる関数その一]
|> Array.map[引きてる関数その二]

この辺りはF#の言語実装として狙ってやったのか、普通に考えたらそうなっちゃうのかは僕にはわからないのですが、結果的にC#のLinqメソッド構文と、F#のPipe-forward演算子を使った構文はかなり似てきます。
こんな感じに。

//F#    
Directory.GetFiles("C:", "*.*", SearchOption.AllDirectories)
|> Array.map (fun file -> new FileInfo(file))
|> Array.map (fun info -> info.Length)
|> Array.sum
 
//C#
Directory.GetFiles("C:", "*.*", SearchOption.AllDirectories)
.Select(file => new FileInfo(file))
.Select(info => info.Length)
.Sum();

Pipe-forward演算子と聞くと身構えてしまいますが、計算順序を入れ替えるならただのシンタックスシュガーと見てもいいのではないでしょうかね?