ストリーム (プログラミング)ストリーム(英: stream)とは、データを、比較的小さい単位が連続したものと捉え、上流から下流へ「流れるもの」とみなし、そのデータの入出力・送受信(途中段階を含む)を最小限の滞留とさせ低遅延処理となるように扱う形態を指す。またその操作のための抽象データ型を指す[1]。 処理内部では適切なデータ分割・バッファリングが行われる。 入力ストリーム (input stream) を利用してデータの読み出しを行ない、出力ストリーム (output stream) を利用してデータの書き込みを行なう。対照的な概念としては、保管・永続化されたデータ形態(ファイル、データベースなど)がある。 メモリバッファの入出力を扱うもの、ネットワーク通信を扱うものなどさまざまなものがある。ファイルの入出力(読み書き)に対しては、ストリームとの変換を行う仕組みが用意される。 典型例として、Unixオペレーティングシステムおよびそのシェルによって実装されたものがある(標準ストリーム、パイプライン、リダイレクト)[2]。 標準ストリーム→詳細は「標準ストリーム」を参照
オペレーティングシステム(例えばUnix)の標準的な入力元や出力先に対して、標準ストリームと呼ばれる特別なストリームが用意される。 キーボードからの入力、ディスプレイへの出力も、標準ストリームによって抽象化され、個別のプログラムからはデバイスハードウェアを意識する必要がなくなる。 C言語C言語ではUnix由来の標準ストリームとして、標準入力 C++入出力ストリームC++では、標準C++ライブラリのヘッダーファイル #include <iostream>
int main()
{
std::cout << "Hello, World!" << std::endl;
return 0;
}
C++は強く型付けされた言語であるが、この標準入出力ストリームは多重定義によって全く型を意識せずに入出力を行なえる。特定の演算子を多重定義したユーザー定義型(クラスあるいは構造体)も利用できるため、非常に柔軟な入出力が可能である。さらに入出力操作子(マニピュレータ)の導入により、細かな制御が可能となった。 #include <iostream>
#include <iomanip>
...
int i;
std::string s;
my_data_type d;
std::cin >> i; // 整数の入力をiに読み込む。
std::cin >> std::setw(10) >> s; // 10文字読み込む。
std::cin >> d; // オーバーロードすることで任意のデータをdに読み込む。
これらの機能により、従来の型消去 (type erasure) や型昇格 (type promotion) を伴う可変長引数を利用した 文字列ストリーム標準ヘッダーのひとつ 外部ライブラリBoost C++ライブラリにおける Javascript→詳細は「JavaScript」を参照
ストリーム API[3]を持つ(WHATWGにより策定が進められている)。 Node.js→詳細は「Node.js」を参照
ストリームを扱うモジュールを持つ。 Java→詳細は「Java」を参照
ストリーム API を持つ。 .NET Framework.NET Frameworkでも入出力をストリームに一般化しており、ここでは低水準な
上記のストリームを読み書きするためのクラスが別途存在し、通常はこれらを用いて入出力処理を行なう。
関数型言語関数型言語においては専ら、無限の大きさ(長さ、要素数)の再帰的なデータ構造を指す。遅延評価を用いて実装されるため「遅延ストリーム」とも呼ばれる。無限のデータを扱うには、そのうちの一部を切り出したりする関数も必要なほか、ストリームを成すデータも再帰関数によって生成されるため、オブジェクト指向の関数型言語では、これらをまとめてストリームクラスとして実装することもある。関数が出力するストリーム自体は連結リストとして実装されることが多い。 遅延評価は必要なときに必要なだけ関数を評価し、不要になったら関数の評価を正常に中断することができる。このことは再帰呼び出しを中断する条件(停止条件)の判定を一切行わない再帰関数や再帰的な値の定義を可能にする。たとえば階乗を求める関数は、1から順に再帰的にかけ算してその結果を返すよう定義するだけである。上限などを設ける必要はなく、かわりに「結果をn個求めてリストにする」関数や「結果をx個捨てる」関数などを介して呼び出す。条件判定をしないということは、遅延評価を行わない言語では無限ループに陥いるということである。しかしそのような言語でも無限の要素数を持つデータを扱えるようにするため、ストリームに関してだけ遅延評価を取り入れている。 無限に再帰する関数や値から一部を取り出したりするしくみは巧妙にできている。「結果をn回求める」関数をrepeat、再帰関数をrecとしてその経過を見る。
サンクは関数を評価した途中経過と見做せる。recを階乗関数factとして3回評価する場合のサンクの状態を(概念的にだが)示す。
fact関数は
カッコの中全体がサンクと言える。また、フォースは「カッコの中と関数をひとつの関数として呼び出すこと」と言える。 遅延評価が標準である言語ではすべての再帰的な定義がストリームのように機能するため、とくにストリームと呼ぶことはない。しかしHaskellにおいては、モナドが導入される以前は、参照透過な入出力を実現するためのデータ構造をストリームと呼んでいた。 脚注
関連項目 |