シーケンスとリストの違いを理解しようとしています。
F# では、この 2 つが明確に区別されます。ただし、C# では、プログラマーが IEnumerable コレクションをシーケンスとして参照するのを見てきました。IEnumerable をシーケンスにするのは、コレクションを反復処理するオブジェクトを返すという事実ですか?
おそらく、本当の違いは純粋に関数型言語に見られるのでしょうか?
そうではありません-リストへのランダムアクセスや、そのカウントをすばやく取得できる傾向があります。確かに、リンクされたリストにはランダムアクセスの性質がありません...しかし、それらは実装しませんIList<T>
. 特定のプラットフォームによって提供される機能と一般的な概念との間には、灰色の領域があります。
シーケンス ( で表されるIEnumerable<T>
) は、読み取り専用、転送専用、一度に 1 つの項目であり、潜在的に無限です。もちろん、シーケンスの任意の実装はリスト (例: List<T>
) でもかまいませんが、それをシーケンスとして扱っている場合は、基本的にそれを (繰り返し) 反復することができ、それだけです。
List<T>
コレクションのようにインターフェイスを実装するという事実から、混乱が生じる可能性があると思いますIEnumerable<T>
。一般にサブタイプの関係がある場合 (例: Shape
2 つのサブタイプRectangle
とを持つスーパータイプCircle
)、その関係を「is-a」階層として解釈できます。
これは、"Circle
は Shape
" であると言ってもまったく問題ないことを意味し、同様に、人々は "List<T>
は IEnumerable<T>
" である、つまり「リストはシーケンスである」と言うでしょう。リストはシーケンスの特別なタイプであるため、これはある程度理にかなっています。一般に、シーケンスは遅延生成および無限にすることもできます (これらの型はリストにすることもできません)。リストによって生成できない (完全に有効な) シーケンスの例は、次のようになります。
// C# version // F# version
IEnumerable<int> Numbers() { let rec loop n = seq {
int i = 0; yield n
while (true) yield return i++; yield! loop(n + 1) }
} let numbers = loop(0)
list
F# の型も を実装しているため、これは F# にも当てはまりますIEnumerable<T>
が、関数型プログラミングはオブジェクト指向の観点をそれほど重視していません (また、「is a」解釈を可能にする暗黙の変換は F# ではあまり使用されません)。
シーケンス コンテンツはオンデマンドで計算されるため、メモリに影響を与えることなく、たとえば無限シーケンスを実装できます。したがって、C# では、たとえばシーケンスを記述できます。
IEnumerable<int> Null() {
yield return 0;
}
ゼロの無限シーケンスを返します。あなたは書ける
int[] array = Null().Take(10).ToArray()
また、シーケンスが無限であるにもかかわらず、10*4 バイトのメモリが必要になります。ご覧のとおり、C# にはシーケンスとコレクションの区別があります。