この記事は「F# Advent Calendar 2015」の 20 日目です。
Streams というライブラリーがあります。このライブラリーは Seq モジュールと同じように扱うことができますが,継続渡しスタイルで実装されています。
基本的には Seq モジュールでできることは, Streams で置き換えることができます。モジュールを Seq から Nessos.Streams.Stream に置き換えるだけです。元の入力が seq<'a>
の場合は, Stream.ofSeq 関数により Stream<'a>
に変換可能です。
open Nessos.Streams data |> Stream.ofSeq |> Stream.filter (fun x -> x % 2 = 0) |> Stream.map (fun x -> x * x)
パフォーマンスも非常によく,常に Seq 以上のパフォーマンスが出ます。また,並列処理版の ParStream モジュールもあるため,容易に並列処理を記述することもできます[A]。
以下は素数を列挙するコードです[B]。
// 素数のチェック // https://msdn.microsoft.com/ja-jp/library/dd233209.aspx から let isPrime n = let rec check i = i > n / 2 || (n % i <> 0 && check (i + 1)) check 2 // Seq 版 let sequence k = Seq.initInfinite id |> Seq.filter (fun p -> p > 1) |> Seq.filter isPrime |> Seq.take k |> Seq.toArray // Stream 版 let stream k = Stream.initInfinite id |> Stream.filter (fun p -> p > 1) |> Stream.filter isPrime |> Stream.take k |> Stream.toArray // ParStream 版 let parstream k = Seq.initInfinite id |> ParStream.ofSeq |> ParStream.filter (fun p -> p > 1) |> ParStream.filter isPrime |> ParStream.take k |> ParStream.toArray
結果は以下のとおりです。 20 回ずつ繰り返し実行した場合の合計時間です。両対数グラフであることに注意してください。
まとめ
Streams はパフォーマンスが良いので Seq を置き換えるのに十分利用できます。また,並列処理も容易に記述できます。覚えておくと便利なライブラリーの一つですね。
ちなみに C# 版の Streams.CSharp というライブラリーも存在します。
脚注
- Seq の並列版の PSeq モジュールは標準ではないので F# Parallel Sequences を導入します。 [↩]
- 効率の良いコードではありませんが,パフォーマンスを確認するのには良い感じです。 [↩]