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

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

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

JavaScript の例(3) (TypeScript)

コンストラクターを1個にしました。イテレーターを保持する変数はやはりクラスの中には書けません。これはどうすれば良いのかわかりません。Visual Studioでこれを実行すると出力が「出力」の領域に出ないので出力がよくわかりません。これは調査したいと思います。

class LongDecimal {
    decimals: Array<number>;
    constructor(numbers: Iterable<number>) {
        this.decimals = [];
        for (var n of numbers) {
            this.decimals.push(n);
        }
    }

    static Align0<T>(xs: T[], len: number, z: T): T[] {
        var result: T[] = [];
        for (var xd of xs) {
            result.push(xd);
        }
        for (var i = xs.length; i < len; i++) {
            result.push(z);
        }
        return result;
    }

    static ZipWith<T, U>(f: (x: T, y: T) => U, xs: T[], ys: T[]): U[] {
        var result: U[] = [];
        for (var i = 0; i < xs.length && i < ys.length; i++) {
            result.push(f(xs[i], ys[i]));
        }
        return result;
    }

    static ZipWith0<T, U>(z: T, f: (x: T, y: T) => U, xs: T[], ys: T[]): U[] {
        var xsx: T[] = LongDecimal.Align0(xs, ys.length, z);
        var ysx: T[] = LongDecimal.Align0(ys, xs.length, z);
        return LongDecimal.ZipWith(f, xsx, ysx);
    }

    static CarryStep(carry_and_dec: [number, LongDecimal], x: number): [number, LongDecimal] {
        var [carry, dec]: [number, LongDecimal] = carry_and_dec;
        var newdec = new LongDecimal([(x + carry) % 10].concat(dec.decimals));
        return [Math.floor((x + carry) / 10), newdec];
    }

    static Replicate<T>(times: number, val: T): T[] {
        var result: T[] = [];
        for (var i = 0; i < times; i++) {
            result.push(val);
        }
        return result;
    }

    static LookUpFirst<T, U>(f: (key: T) => boolean, pairs: [T, U][]): U {
        for (var [key, val] of pairs) {
            if (f(key)) {
                return val;
            }
        }
        // 見つからないときは何も返さない
    }

    Sum_1(n: number): LongDecimal {
        return new LongDecimal([this.decimals[0] + n].concat(this.decimals.slice(1)));
    }

    Decimalize(c: number, leave: boolean): LongDecimal {
        var [carry, dec]: [number, LongDecimal] = this.decimals.reduceRight(LongDecimal.CarryStep, [c, new LongDecimal([])]);
        if (leave && carry != 0) {
            return dec.Sum_1(carry * 10);
        }
        else {
            return dec;
        }
    }

    Shift(e: number): LongDecimal {
        return new LongDecimal(LongDecimal.Replicate(e, 0).concat(this.decimals));
    }

    Product_1(xd: number): LongDecimal {
        return new LongDecimal(this.decimals.map(yd => xd * yd));
    }

    CollectShiftMult(y: LongDecimal): LongDecimal[] {
        var result: LongDecimal[] = [];
        var e = 0;
        for (var xd of this.decimals) {
            result.push(y.Product_1(xd).Shift(e));
            e++;
        }
        return result;
    }

    static EqualAndLess(x: number, y: number): [boolean, boolean] {
        return [x == y, x < y];
    }

    Sum(y: LongDecimal): LongDecimal {
        var x: LongDecimal = this;
        return new LongDecimal(LongDecimal.ZipWith0(0, (a, b) => a + b, x.decimals, y.decimals)).Decimalize(0, true);
    }

    Difference(y: LongDecimal): LongDecimal {
        var x: LongDecimal = this;
        var yds: number[] = LongDecimal.Align0(y.decimals, x.decimals.length, 0);
        return new LongDecimal(LongDecimal.ZipWith0(0, (a, b) => a + b, x.decimals, yds.map(a => 9 - a))).Decimalize(1, false);
    }

    Product(y: LongDecimal): LongDecimal {
        var x: LongDecimal = this;
        return x.CollectShiftMult(y).reduce((a, b) => a.Sum(b), new LongDecimal([]));
    }

    Equal(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        return LongDecimal.ZipWith0(0, (a, b) => a == b, x.decimals, y.decimals).every(b => b);
    }

    NotEqual(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        return !(x.Equal(y));
    }

    Less(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        if (x.Equal(y)) {
            return false;
        }
        return LongDecimal.LookUpFirst(key => !key, LongDecimal.ZipWith0(0, LongDecimal.EqualAndLess, x.decimals, y.decimals));
    }

    LessOrEqual(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        return x.Less(y) || x.Equal(y);
    }

    Greater(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        return !(x.LessOrEqual(y));
    }

    GreaterOrEqual(y: LongDecimal): boolean {
        var x: LongDecimal = this;
        return !(x.Less(y));
    }
    Print(): string {
        var res: string = "";
        var count: number = 0;
        for (var d of this.decimals) {
            if (count == 1) {
                res += ".";
            }
            res += d;
            count++;
        }
        return res;
    }
}

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

    get CurrentDigit(): number {
        return this.current_digit;
    }

    GetNextDecimalDigit(): number {
        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)) {
                this.number = this.number.Sum(zd);
                this.square_difference = this.square_difference.Difference(number_sq_diff);
                this.scale++;
                this.current_digit = dd;
                return dd;
            }
        }
        return 0;
    }
}

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 (; ;) {
            yield nums.GetNextDecimalDigit();
        }
    }
}

class NumbersServer {
    current_numbers: Numbers;

    GetNumbers(numbers: Numbers): Numbers {
        var current = generator_server_gen.next(numbers);
        return current.value;
    }

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

    *GenerateDecimalServer(): Iterable<Numbers> {
        var number: LongDecimal = new LongDecimal([]);
        var square_difference: LongDecimal = new LongDecimal([3]);
        var current_numbers: Numbers = new Numbers(number, square_difference, 0);
        for (; ;) {
            current_numbers = yield current_numbers;
        }
    }
}

var generator_gen;
var generator_server_gen;

function* Iterate<T>(next: (T) => T, init: T): Iterable<T> {
    for (; ;) {
        yield init;
        init = next(init);
    }
}

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

function* Map_<T>(f: (T) => T, list: Iterable<T>): Iterable<T> {
    for (var d of list) {
        yield f(d);
    }
}

function NextNumbers(numbers): Numbers {
    numbers.GetNextDecimalDigit();
    return numbers;
}

function Repeat(count: number, f: () => string): string {
    var res: string = "";
    for (var i = 0; i < count; i++) {
        res = f();
    }
    return res;
}

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 {
        for (var e = 0; e < this.count; e++) {
            this.result_number = this.result_number.Sum(new LongDecimal([this.generator.GetNextDecimalDigit()]).Shift(e));
        }
        return this.result_number.Print();
    }

    RepeatServer(): string {
        for (var e = 0; e < this.count; e++) {
            var current_numbers = this.generator_server.GetNumbers(current_numbers);
            var dd = current_numbers.GetNextDecimalDigit();
            this.generator_server.SetNumbers(current_numbers);
            this.result_number = this.result_number.Sum(new LongDecimal([dd]).Shift(e));
        }
        return this.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);
        init_numbers.GetNextDecimalDigit();
        return new LongDecimal(Map_(numbers => numbers.CurrentDigit, Take(this.count, Iterate(NextNumbers, init_numbers)))).Print();
    }
}

console.log(new Calc().RepeatGenerator());
console.log(new Calc().RepeatServer());
console.log(new Calc().IterateGenerator());
console.log(new Calc().IterateServer());