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

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

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

C# の例(15) (タプル)

Lisp への移植用にタプルを使って書き直しました。

    internal class Calc
    {
        private const int count = 21;
        private static IEnumerable<int> Take(int count, (Func<bool> next, Func<int> getCurrent, Action<int> setCurrent) iter)
        {
            for (int i = 0; i < count && iter.next(); i++)
            {
                yield return iter.getCurrent();
            }
        }
        private static IEnumerable<U> UnfoldL<T, U>(Func<T, (U, T)> next, T init)
        {
            (U dst, T src) = next(init);
            // 終了したとき next は src == null を返すとする
            if (src == null)
            {
                yield break;
            }
            yield return dst;
            // ここは foreach を使わないと書けない
            foreach (U e in UnfoldL(next, src))
            {
                yield return e;
            }
        }
        private static (int, (LongDecimal, LongDecimal, int)) GetNextDecimalDigitAndNumbers((LongDecimal, LongDecimal, int) numbers)
        {
            (LongDecimal number, LongDecimal square_difference, int scale) = numbers;
            (int, (LongDecimal, LongDecimal, int)) maxdd(int dd)
            {
                if (dd >= 0)
                {
                    LongDecimal two = new LongDecimal(2);
                    LongDecimal zd = new LongDecimal(dd).Shift(scale);
                    LongDecimal number_sq_diff = number * zd * two + zd * zd;
                    if (number_sq_diff <= square_difference)
                    {
                        return (dd, (number + zd, square_difference - number_sq_diff, scale + 1));
                    }
                    return maxdd(dd - 1);
                }
                return (0, (null, null, 0));
            }
            return maxdd(9);
        }
        private static (Func<bool> next, Func<int> getCurrent, Action<int> setCurrent) GenerateDecimal()
        {
            LongDecimal number = new LongDecimal();
            LongDecimal square_difference = new LongDecimal(3);
            (LongDecimal, LongDecimal, int) nums = (number, square_difference, 0);
            int current_digit = 0;
            bool next()
            {
                (current_digit, nums) = GetNextDecimalDigitAndNumbers(nums);
                return true;
            }
            int getCurrent()
            {
                return current_digit;
            }
            void setCurrent(int val)
            {
            }
            return (next, getCurrent, setCurrent);
        }
        public static string RepeatGenerator()
        {
            LongDecimal number = new LongDecimal();
            LongDecimal square_difference = new LongDecimal(3);
            (LongDecimal, LongDecimal, int) nums = (number, square_difference, 0);
            (Func<bool> next, Func<int> getCurrent, Action<int> setCurrent) generator = GenerateDecimal();
            int GetNextDecimalDigit()
            {
                generator.next();
                return generator.getCurrent();
            }
            LongDecimal repeat(LongDecimal number, int e, int count)
            {
                if (e < count)
                {
                    return repeat(number + new LongDecimal(GetNextDecimalDigit()).Shift(e), e + 1, count);
                }
                else
                {
                    return number;
                }
            }
            LongDecimal result_number = repeat(new LongDecimal(), 0, count);
            return result_number.Print();
        }
        public static string IterateGenerator()
        {
            return new LongDecimal(Take(count, GenerateDecimal())).Print();
        }
        public static string RepeatServer()
        {
            LongDecimal number = new LongDecimal();
            LongDecimal square_difference = new LongDecimal(3);
            (LongDecimal, LongDecimal, int) current_numbers = (number, square_difference, 0);
            LongDecimal repeat(LongDecimal number, int e, int count)
            {
                if (e < count)
                {
                    (LongDecimal, LongDecimal, int) numbers = current_numbers;
                    (int dd, (LongDecimal, LongDecimal, int) ns) = GetNextDecimalDigitAndNumbers(numbers);
                    current_numbers = ns;
                    return repeat(number + new LongDecimal(dd).Shift(e), e + 1, count);
                }
                else
                {
                    return number;
                }
            }
            LongDecimal result_number = repeat(new LongDecimal(), 0, count);
            return result_number.Print();
        }
        public static string IterateServer()
        {
            LongDecimal number = new LongDecimal();
            LongDecimal square_difference = new LongDecimal(3);
            (LongDecimal, LongDecimal, int) init_numbers = (number, square_difference, 0);
            return new LongDecimal(UnfoldL(GetNextDecimalDigitAndNumbers, init_numbers).Take(count)).Print();
        }
    }