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

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

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

JavaScript の例(7) (TypeScript)

TypeScript 版の他のクラスも同様に書き直します。

class Numbers {
    number: LongDecimal;
    square_difference: LongDecimal;
    scale: number;
    constructor(number: LongDecimal, square_difference: LongDecimal, scale: number) {
        this.number = number;
        this.square_difference = square_difference;
        this.scale = scale;
    }

    GetNextDecimalDigitAndNumbers(): [number, Numbers] {
        var two: LongDecimal = new LongDecimal([2]);
        for (var dd: number = 9; dd >= 0; dd--) {
            var zd: LongDecimal = new LongDecimal([dd]).Shift(this.scale);
            var number_sq_diff: LongDecimal = this.number.Product(zd).Product(two).Sum(zd.Product(zd));
            if (number_sq_diff.LessOrEqual(this.square_difference)) {
                const new_number = this.number.Sum(zd);
                const new_square_difference = this.square_difference.Difference(number_sq_diff);
                return [dd, new Numbers(new_number, new_square_difference, this.scale + 1)];
            }
        }
        return null;
    }
}

class NumbersGenerator {
    GetNextDecimalDigit(): number {
        return generator_gen.next().value;
    }

    *GenerateDecimal(): Iterable<number> {
        var number: LongDecimal = new LongDecimal([]);
        var square_difference: LongDecimal = new LongDecimal([3]);
        var nums: Numbers = new Numbers(number, square_difference, 0);
        for (; ;) {
            var d_ns = nums.GetNextDecimalDigitAndNumbers();
            nums = d_ns[1];
            yield d_ns[0];
        }
    }
}

class NumbersServer {
    current_numbers: Numbers;

    constructor() {
        var number: LongDecimal = new LongDecimal([]);
        var square_difference: LongDecimal = new LongDecimal([3]);
        this.current_numbers = new Numbers(number, square_difference, 0);
    }

    GetNumbers(): Numbers {
        return this.current_numbers;
    }

    SetNumbers(numbers): void {
        this.current_numbers = numbers;
    }

    *GenerateDecimalServer(): Iterable<Numbers> {
        for (; ;) {
            this.current_numbers = yield this.current_numbers;
        }
    }
}

var generator_gen;
var generator_server_gen;

function* UnfoldL(next: string, init) {
    var cpl = Func[next].Apply(init);
    // 終了したとき next は null を返すとする
    if (cpl == null) {
        return;
    }
    yield cpl[0];
    // ここは for を使わないと書けない
    for (var e of UnfoldL(next, cpl[1])) {
        yield e;
    }
}

function* Take<T>(n: number, generator: Iterable<T>): Iterable<T> {
    var count = 0;
    for (var d of generator) {
        if (count == n) {
            break;
        }
        count++;
        yield d;
    }
}

class Calc {
    count: number;
    generator: NumbersGenerator;
    generator_server: NumbersServer;
    result_number: LongDecimal;

    constructor() {
        this.count = 21;
        this.generator = new NumbersGenerator();
        this.generator_server = new NumbersServer();
        this.result_number = new LongDecimal([]);
        generator_gen = this.generator.GenerateDecimal();
        generator_server_gen = this.generator_server.GenerateDecimalServer();
    }

    RepeatGenerator(): string {
        var repeat = function (number: LongDecimal, e: number, count: number, generator: NumbersGenerator): LongDecimal {
            if (e < count) {
                return repeat(number.Sum(new LongDecimal([generator.GetNextDecimalDigit()]).Shift(e)), e + 1, count, generator);
            } else {
                return number;
            }
        }
        var result_number: LongDecimal = repeat(new LongDecimal([]), 0, this.count, this.generator);
        return result_number.Print();
    }

    RepeatServer(): string {
        var repeat = function (number: LongDecimal, e: number, count: number, server: NumbersServer): LongDecimal {
            if (e < count) {
                var current_numbers = server.GetNumbers();
                var d_ns = current_numbers.GetNextDecimalDigitAndNumbers();
                var dd = d_ns[0];
                server.SetNumbers(d_ns[1]);
                return repeat(number.Sum(new LongDecimal([dd]).Shift(e)), e + 1, count, server);
            } else {
                return number;
            }
        }
        var result_number: LongDecimal = repeat(new LongDecimal([]), 0, this.count, this.generator_server);
        return result_number.Print();
    }

    IterateGenerator(): string {
        return new LongDecimal(Take(this.count, this.generator.GenerateDecimal())).Print();
    }

    IterateServer(): string {
        var number = new LongDecimal([]);
        var square_difference = new LongDecimal([3]);
        var init_numbers = new Numbers(number, square_difference, 0);
        return new LongDecimal(Take(this.count, UnfoldL("NextDigitAndNumbers", init_numbers))).Print();
    }
}

Func には以下のものを追加します。

    NextDigitAndNumbers: {
        Apply(x: Numbers): [number, Numbers] {
            return x.GetNextDecimalDigitAndNumbers();
        }
    },