Qsort( Rand().Take(10) ) で何が起こったのか?

新年度なので模様替えしてみました。

さて、昨日のQsortにRandを食わせるとどうなるか?軽く見てみます。
TakeをLINQのSequence.csを、RandはNyaRuRuさんのものをちょっといじったものを用意したので、昨日のコードとくっつけると実行できます。昨日のコードも今日のコードも簡単のため、エラーチェックが雑です、ご注意を。一応念のため。

10個は多いので2つを取ろうとTake(2)で何度か実行してみると、3つ出てきたり、1つしか出てこなかったりと、めちゃくちゃでした。
原因はすでに書いたとおりQsort()の中で何度もIEnumeratorを取り出したため、Rand()が何度も生成されるため。Random()はシステム時計をシードに取るので新たに生成されると異なる系が出てきます(って知らなかったw)。
コールグラフを書きたかったけど、大変なので断念。ぱっと見の印象よりもさらに深いツリーになるなぁと感じました。yieldが出てくるとツリーの深さが頭でイメージできないです。一度さわりだけでもステップインで追いかけて深さを体験してみるとおもしろいですよ。

public static void Main()
{
	foreach ( int e in Qsort( Take<int>( Rand(), 2 ) ) )
	{
		Console.WriteLine( "{0,10}", e );
	}
	Console.ReadLine();
}

static IEnumerable<T> Take<T>( IEnumerable<T> source, int count )
{
	if ( count > 0 )
	{
		foreach ( T element in source )
		{
			yield return element;
			if ( --count == 0 ) break;
		}
	}
}

public static IEnumerable<int> Rand()
{
	Console.WriteLine( "Generated" );
	Random rand = new Random();
	while ( true )
	{
		int x = rand.Next();
		Console.WriteLine( "Gen:{0,10}", x );
		yield return x;
	}
}

このRand()って無限列挙ですね。遅延評価のおかげで無限を扱ってるような幻想を抱いているわけです。