エレファント・コンピューティング調査報告

極限に関する順序を論理プログラミングの手法を使って指定することを目指すブロクです。

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

C# の例(8)

Channel を使ったイテレーターのクラス IteratorChannelImpl を作成しました。「ConfigureAwait(false)」というのは「これがないと await の前後が同じスレッドで実行されるので Result を取得することができない」という仕様らしいです。意味がよくわからなくで気持ち悪いのですが、今回は複数スレッドで実行することが目的ではないので、この仕様に従うことにします。

    internal class IteratorChannelImpl<T>
    {
        private Channel<T> ch_get;
        private T? current;
        public IteratorChannelImpl(Channel<T> ch_get)
        {
            this.ch_get = ch_get;
        }
        public T? Current
        {
            get
            {
                return current;
            }
        }
        private async Task<bool> GetFromServer_a()
        {
            if (!await ch_get.Reader.WaitToReadAsync().ConfigureAwait(false))
            {
                return false;
            }
            if (!ch_get.Reader.TryRead(out current))
            {
                return false;
            }
            return true;
        }
        private bool GetFromServer()
        {
            return GetFromServer_a().Result;
        }
        public bool MoveNext()
        {
            if (!GetFromServer())
            {
                return false;
            }
            return true;
        }
        public IEnumerable<T?> Take(int count)
        {
            IteratorChannelImpl<T> it = this;
            for (int i = 0; i < count && it.MoveNext(); i++)
            {
                yield return it.Current;
            }
        }
    }
        private void button3_Click(object sender, EventArgs e)
        {
            IteratorClass iterator = new IteratorClass();
            Channel<int> ch_get = Channel.CreateBounded<int>(1);
            Task task = Task.Run(() => iterator.Generator(ch_get));
            IteratorChannelImpl<int> iter = new IteratorChannelImpl<int>(ch_get);
            string res = "";
            while (iter.MoveNext())
            {
                res += iter.Current.ToString() + " ";
            }
            textBox1.Text = res;
        }

実行結果: 0 1 2 3 4 5 6 7 8 9

仮想サーバーへの get と set の両方があるイテレーターのクラス IteratorChannelIOImpl は以下のようになります。

    internal class IteratorChannelIOImpl<T>
    {
        private Channel<T> ch_get;
        private Channel<T> ch_set;
        private T? current;
        public IteratorChannelIOImpl(Channel<T> ch_get, Channel<T> ch_set)
        {
            this.ch_get = ch_get;
            this.ch_set = ch_set;
            GetFromServer(); // 最初の値を取得
        }
        public T? Current
        {
            get
            {
                return current;
            }
            set
            {
                current = value;
            }
        }
        private async Task<bool> GetFromServer_a()
        {
            if (!await ch_get.Reader.WaitToReadAsync().ConfigureAwait(false))
            {
                return false;
            }
            if (!ch_get.Reader.TryRead(out current))
            {
                return false;
            }
            return true;
        }
        private bool GetFromServer()
        {
            return GetFromServer_a().Result;
        }
        private async Task<bool> SetToServer_a()
        {
            if (!await ch_set.Writer.WaitToWriteAsync().ConfigureAwait(false))
            {
                return false;
            }
            if (!ch_set.Writer.TryWrite(current))
            {
                return false;
            }
            return true;
        }
        private bool SetToServer()
        {
            return SetToServer_a().Result;
        }
        public bool MoveNext()
        {
            if (!SetToServer())
            {
                return false;
            }
            if (!GetFromServer())
            {
                return false;
            }
            return true;
        }
        public IEnumerable<T?> Take(int count)
        {
            IteratorChannelIOImpl<T> it = this;
            for (int i = 0; i < count && it.MoveNext(); i++)
            {
                yield return it.Current;
            }
        }
    }
        private void button4_Click(object sender, EventArgs e)
        {
            IteratorClass iterator = new IteratorClass();
            Channel<int> ch_get = Channel.CreateBounded<int>(1);
            Channel<int> ch_set = Channel.CreateBounded<int>(1);
            Task task = Task.Run(() => iterator.GeneratorIO(ch_get, ch_set));
            IteratorChannelIOImpl<int> iter = new IteratorChannelIOImpl<int>(ch_get, ch_set);
            string res = "";
            while (iter.MoveNext())
            {
                res += iter.Current.ToString() + " ";
                iter.Current = iter.Current * 2;
            }
            textBox1.Text = res;
        }

実行結果: 1 2 4 8 16 32 64 128 256

前回より1個少なくなりましたが良しとします。