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

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

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

F# の例(2)

F# もコンストラクターを3個に削減しました。Seq.unfold (iterate に相当)を使っています。

let Align0<'T> (xs: 'T list) (len: int) (z: 'T): 'T list =
    [
        for xd in xs do yield xd
        for i in xs.Length .. len - 1 do yield z
    ]
let ZipWith0<'T, 'U> (z: 'T) (f: 'T -> 'T -> 'U) (xs: 'T list) (ys: 'T list): 'U list =
    let xsx = Align0 xs (List.length ys) z
    let ysx = Align0 ys (List.length xs) z
    List.map2 f xsx ysx
let FoldL0<'T, 'U> (z: 'U) (f: 'U -> 'T -> 'U) (xs: 'T list): 'U =
    let mutable a = z
    for x in xs do
        a <- f a x
    a
let FoldR0<'T, 'U> (z: 'U) (f: 'U -> 'T -> 'U) (xs: 'T list): 'U =
    FoldL0 z f (List.rev xs)
let EqualAndLess (x: int) (y: int): bool * bool =
    (x = y, x < y)

type LongDecimal(numbers: int list) =
    let mutable decimals_: int list = numbers
    new() = LongDecimal([])
    new(n: int) = LongDecimal([n])
    member this.decimals = decimals_
    static member CarryStep_ (carry_and_dec: int * LongDecimal) (x: int): int * LongDecimal =
        let (carry, dec): int * LongDecimal = carry_and_dec
        let newdec = new LongDecimal([(x + carry) % 10] @ dec.decimals)
        ((x + carry) / 10, newdec)
    member this.Decimalize (c: int, leave: bool): LongDecimal =
        let (carry, dec) = FoldR0 (c, new LongDecimal()) LongDecimal.CarryStep_ this.decimals
        if leave && carry <> 0 then
            dec + carry * 10
        else
            dec
    member this.Shift (e: int): LongDecimal =
        (new LongDecimal([ for i in 1 .. e -> 0 ] @ this.decimals))
    member this.CollectShiftMult (y: LongDecimal): LongDecimal list =
        [
            let mutable e: int = 0
            for xd in this.decimals do
                yield (y * xd).Shift(e)
                e <- e + 1
        ]
    static member (+) (x: LongDecimal, n: int): LongDecimal =
        new LongDecimal([(List.head x.decimals) + n] @ List.skip 1 x.decimals)
    static member (+) (x: LongDecimal, y: LongDecimal): LongDecimal =
        (new LongDecimal(ZipWith0 0 (fun a b -> a + b) x.decimals y.decimals)).Decimalize(0, true)
    static member (-) (x: LongDecimal, y: LongDecimal): LongDecimal =
        let yds = Align0 y.decimals (List.length x.decimals) 0
        (new LongDecimal(ZipWith0 0 (fun a b -> a + b) x.decimals (List.map (fun a -> 9 - a) yds))).Decimalize(1, false)
    static member (*) (x: LongDecimal, xd: int): LongDecimal =
        new LongDecimal(List.map (fun (yd: int) -> xd * yd) x.decimals)
    static member (*) (x: LongDecimal, y: LongDecimal): LongDecimal =
        List.fold (fun a b -> a + b) (new LongDecimal()) (x.CollectShiftMult y)
    static member LessOrEqual (x: LongDecimal, y: LongDecimal): bool =
        let equal = List.forall (fun b -> b) (ZipWith0<int, bool> 0 (fun a b -> a = b) x.decimals y.decimals)
        if equal then
            false
        else
            let get_not_eq (eq, lt) = not eq
            let (eq, lt) = List.find get_not_eq (ZipWith0 0 EqualAndLess x.decimals y.decimals)
            lt
    member this.Print() =
        let mutable res: string = "";
        let mutable count: int = 0;
        for d in this.decimals do
            if count = 1 then
                res <- res + "."
            res <- res + d.ToString();
            count <- count + 1
        res

type Numbers(number: LongDecimal, square_difference: LongDecimal, scale: int) =
    let mutable current_digit = 0
    let mutable number: LongDecimal = number
    let mutable square_difference: LongDecimal = square_difference
    let mutable scale: int = scale
    member this.CurrentDigit: int = current_digit
    member this.GetNextDecimalDigit: int =
        let two: LongDecimal = new LongDecimal(2)
        current_digit <- -1
        for dd = 9 downto 0 do
            if current_digit < 0 then
                let zd: LongDecimal = (new LongDecimal(dd)).Shift(scale)
                let number_sq_diff: LongDecimal = number * zd * two + zd * zd
                if LongDecimal.LessOrEqual (number_sq_diff, square_difference) then
                    number <- number + zd;
                    square_difference <- square_difference - number_sq_diff
                    scale <- scale + 1
                    current_digit <- dd
        current_digit

type NumbersGenerator() =
    let GenerateDecimal() =
        let number: LongDecimal = new LongDecimal()
        let square_difference: LongDecimal = new LongDecimal(3)
        let nums: Numbers = new Numbers(number, square_difference, 0)
        seq {
            while true do yield nums.GetNextDecimalDigit
        }
    let generator = GenerateDecimal().GetEnumerator()
    member this.GetNextDecimalDigit =
        let b = generator.MoveNext()
        generator.Current
    member this.GenerateDecimal_() =
        let number: LongDecimal = new LongDecimal()
        let square_difference: LongDecimal = new LongDecimal(3)
        let nums: Numbers = new Numbers(number, square_difference, 0)
        seq {
            while true do yield nums.GetNextDecimalDigit
        }

type NumbersServer() =
    let mutable current_numbers: Numbers = new Numbers(new LongDecimal(), new LongDecimal(), 0)
    let GenerateDecimalServer() =
        let number: LongDecimal = new LongDecimal()
        let square_difference: LongDecimal = new LongDecimal(3)
        current_numbers <- new Numbers(number, square_difference, 0)
        seq {
            while true do yield current_numbers
        }
    let generator_server = GenerateDecimalServer().GetEnumerator()
    member this.GetNumbers: Numbers =
        let b = generator_server.MoveNext()
        generator_server.Current
    member this.SetNumbers(numbers: Numbers): unit =
        current_numbers <- numbers
    member this.Numbers
        with get(): Numbers =
            this.GetNumbers
        and set(value: Numbers) =
            this.SetNumbers value
    member this.GenerateDecimalServer_() =
        let number: LongDecimal = new LongDecimal()
        let square_difference: LongDecimal = new LongDecimal(3)
        current_numbers <- new Numbers(number, square_difference, 0)
        seq {
            while true do yield current_numbers
        }

let NextNumbers (numbers: Numbers): (Numbers * Numbers) option =
    let n = numbers.GetNextDecimalDigit
    Some (numbers, numbers)

type Calc() =
    let mutable generator: NumbersGenerator = new NumbersGenerator()
    let mutable generator_server: NumbersServer = new NumbersServer()
    let mutable result_number: LongDecimal = new LongDecimal()
    let mutable count: int = 21

    member this.RepeatGenerator(): string =
        for e = 0 to count - 1 do
            result_number <- result_number + (new LongDecimal(generator.GetNextDecimalDigit)).Shift(e)
        result_number.Print()

    member this.RepeatServer(): string =
        for e = 0 to count - 1 do
            let numbers: Numbers = generator_server.Numbers
            let dd: int = numbers.GetNextDecimalDigit
            generator_server.Numbers <- numbers
            result_number <- result_number + (new LongDecimal(dd)).Shift(e)
        result_number.Print()

    member this.IterateGenerator(): string =
        let list = Seq.toList (Seq.take (count) (generator.GenerateDecimal_()))
        (new LongDecimal(list)).Print()

    member this.IterateServer(): string =
        let number: LongDecimal = new LongDecimal()
        let square_difference: LongDecimal = new LongDecimal(3)
        let init_numbers: Numbers = new Numbers(number, square_difference, 0)
        let list = Seq.toList (Seq.take (count) (Seq.map (fun (numbers: Numbers) -> numbers.CurrentDigit) (Seq.unfold NextNumbers init_numbers)))
        (new LongDecimal(list)).Print();

printfn "%s" ((new Calc()).RepeatGenerator())
printfn "%s" ((new Calc()).RepeatServer())
printfn "%s" ((new Calc()).IterateGenerator())
printfn "%s" ((new Calc()).IterateServer())

実行結果

1.73205080756887729352
1.73205080756887729352
1.73205080756887729352
1.73205080756887729352