第37回では,リスト演算を効率化する「fold/build」という融合変換の手法を紹介しました。また,この回のコラムでは,「destroy/unfoldr」という手法にも言及しました。

 リストなどのデータ構造を使う処理に対する融合変換の手法は,ほかにもあります。第10回および第24回のコラムで紹介したデータ並列Haskellの「DPHライブラリ」や,DPHライブラリから派生した「vectorパッケージ」などで利用されている「Stream Fusion」という手法です。今回は,Stream Fusionの基礎を解説します(参考リンク1参考リンク2)。

HackageDBで提供されるstream-fusionパッケージ

 Stream Fusionは,DPHライブラリやvectorパッケージで使われています。ただし,これらのライブラリやパッケージでは,Stream Fusionによる融合変換以外にもプログラムの効率化を図る様々な工夫が行われています。例えば,DPHライブラリではライブラリを階層構造にすることで,それぞれのレベルで別の効率化を行っています。またvectorパッケージでは,Stream Fusionに加えてRecyclingという融合変換の手法が用いられています。これら二つの融合変換を組み合わせることで,vectorが提供するデータ型に応じた効率化を図っています(参考リンク)。DPHやvectorで行われている効率化を説明しようとすると,実際にはStream Fusion以外の説明も必要になります。

 そこで,今回はStream Fusionの効率化の例として,HackageDBで提供されている「stream-fusion」というパッケージを取り上げることにします。stream-fusionは,PreludeモジュールやData.Listモジュールで提供されるようなリスト演算に対し,fold/buildではなくStream Fusionを使って融合変換を行うものです。

 stream-fusionのバージョン0.1.2.2では,以下のモジュールが提供されています。

$ ghc-pkg field stream-fusion version,exposed-modules
version: 0.1.2.2
exposed-modules: Data.Stream Data.List.Stream Control.Monad.Stream

 baseパッケージのモジュールと区別するため,stream-fusionではData.List.StreamControl.Monad.Streamのように末尾に「.Stream」を加えた名前が使われています。baseパッケージで提供される基本的なモジュールは,様々なプログラムやライブラリの実装で広く利用されています。このため,baseパッケージとstream-fusionパッケージのモジュール名が衝突しないように名前を区別しているのです。

 GHCでは,実際には同名のモジュールが異なるパッケージに存在する場合もあります。例えば,baseパッケージの4.x系と3.x系には,同名のモジュールが用意されています。しかし,これらのモジュールはあくまで互換性のために同名になっているに過ぎません。異なるパッケージに存在する同名のモジュールを区別するには,処理系のパッケージ管理機能を使う必要があります。

 基本的には,異なるものを同じ名前で呼ぶことは,ソースコードの保守性を極端に悪くします。baseのようによく利用されるパッケージのモジュール名と同じモジュール名を使うのは避けるべきです(参考リンク1参考リンク2)。