エレファント・ビジュアライザー調査記録

ビジュアルプログラミングで数式の変形を表すことを考えていくブロクです。

関数プログラミングと無限論理多項式(9)

C# の例(4)

このあたりから本題に入ります。イテレーターの yield のような機能がないプログラミング言語用に、クロージャーを使ってイテレーターを実装します。C# ではデリゲートというものを使うのですが、デリゲートという用語の定義はいろいろと細かいことになっていてめんどうなので、ここではクロージャーと呼ぶことにします。

まず IEnumerable インターフェイスを満たすクラスを作って実装します。イテレーターに対する入力もできるようにします。

サーバーで無限に計算する場合

NumbersGenerator クラスの GenerateDecimal は以下のようになります。next と getCurrent がクロージャーで、new IteratorImpl(next, getCurrent) でイテレーターを作成します。current_digit に値を保存しています。このクラスではイテレーターに対する入力は行いません。

        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 インターフェイスを満たすクラス IteratorImpl クラスは以下のようになります。

    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(next, getCurrent, setCurrent) でイテレーターを作成します。current_numbers に値を保存しています。このクラスでは setCurrent でイテレーターに対する入力を行うことができます。

        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 インターフェイスを満たし setCurrent で入力もできるクラス IteratorIOImpl クラスは以下のようになります。

    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