C# の例(4)
このあたりから本題に入ります。イテレーターの yield のような機能がないプログラミング言語用に、クロージャーを使ってイテレーターを実装します。C# ではデリゲートというものを使うのですが、デリゲートという用語の定義はいろいろと細かいことになっていてめんどうなので、ここではクロージャーと呼ぶことにします。
まず IEnumerable
サーバーで無限に計算する場合
NumbersGenerator クラスの GenerateDecimal は以下のようになります。next と getCurrent がクロージャーで、new IteratorImpl
public IEnumerable<int> GenerateDecimal() { LongDecimal number = new LongDecimal(); LongDecimal square_difference = new LongDecimal(3); Numbers nums = new Numbers(number, square_difference, 0); int current_digit = 0; bool next() { current_digit = nums.GetNextDecimalDigit(); return true; } int getCurrent() { return current_digit; } return new IteratorImpl<int>(next, getCurrent); }
IEnumerable
internal class IteratorImpl<T> : IEnumerable<T> { private Func<bool> next; private Func<T> getCurrent; public IteratorImpl(Func<bool> next, Func<T> getCurrent) { this.next = next; this.getCurrent = getCurrent; } public IEnumerator<T> GetEnumerator() { return new EnumeratorImpl(next, getCurrent); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public class EnumeratorImpl: IEnumerator<T> { private Func<bool> next; private Func<T> getCurrent; public EnumeratorImpl(Func<bool> next, Func<T> getCurrent) { this.next = next; this.getCurrent = getCurrent; } public T Current { get { return getCurrent(); } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { return next(); } public void Reset() { } public void Dispose() { } } }
ブラウザーで計算する場合
NumbersServer クラスの GenerateDecimalServer と コンストラクター とイテレーターを保持する変数の定義は以下のようになります。next と getCurrent と setCurrent がクロージャーで、IteratorIOImpl
public NumbersServer() { generator_server = (IteratorIOImpl<Numbers>.EnumeratorImpl)(GenerateDecimalServer()).GetEnumerator(); } private IteratorIOImpl<Numbers>.EnumeratorImpl generator_server;
public IteratorIOImpl<Numbers> GenerateDecimalServer() { LongDecimal number = new LongDecimal(); LongDecimal square_difference = new LongDecimal(3); Numbers current_numbers = new Numbers(number, square_difference, 0); bool next() { return true; } Numbers getCurrent() { return current_numbers; } void setCurrent(Numbers numbers) { current_numbers = numbers; } return new IteratorIOImpl<Numbers>(next, getCurrent, setCurrent); }
IEnumerable
internal class IteratorIOImpl<T> : IEnumerable<T> { private Func<bool> next; private Func<T> getCurrent; private Action<T> setCurrent; public IteratorIOImpl(Func<bool> next, Func<T> getCurrent, Action<T> setCurrent) { this.next = next; this.getCurrent = getCurrent; this.setCurrent = setCurrent; } public IEnumerator<T> GetEnumerator() { return new EnumeratorImpl(next, getCurrent, setCurrent); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public class EnumeratorImpl : IEnumerator<T> { private Func<bool> next; private Func<T> getCurrent; private Action<T> setCurrent; public EnumeratorImpl(Func<bool> next, Func<T> getCurrent, Action<T> setCurrent) { this.next = next; this.getCurrent = getCurrent; this.setCurrent = setCurrent; } public T Current { get { return getCurrent(); } set { setCurrent(value); } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { return next(); } public void Reset() { } public void Dispose() { } } }
実行結果
1.73205080756887729352
1.73205080756887729352
1.73205080756887729352
1.73205080756887729352