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(); } }