今回は ChatGPT で Python から F# に書き換えたのですが、これはそのままでは動かなくて、かなり書き直しました。
このプログラムの mutable な変数を mutable ではないものに変更するとどうなるか、ということを考えたいのですが、これはなかなか難しそうです。以前このブログで取り上げたときも、とくに何もできていませんでした。今回も同じことになりそうなので、ブログに書く意味があるのか、と思いますがいちおう ChatGPT をちょっと使ったということで書いておくことにします。
open System open System.Collections.Generic let formatDecimal (dec: int seq) = let declist: int list = Seq.toList dec let head = declist.Head let tail = declist.Tail |> List.map string |> String.concat "" sprintf "%d.%s" head tail // decimal 型に対するべき乗演算子 let rec ( ** ) (d: decimal) (exp: int) = if exp = 0 then 1M elif exp > 0 then d ** (exp - 1) * d else d ** (exp + 1) / d // 数値クラスの定義 type Numbers(number: decimal, squareDifference: decimal, scale: int) = let mutable number = number let mutable squareDifference = squareDifference let mutable scale = scale member _.Copy() = Numbers(number, squareDifference, scale) member _.GetNextDecimalDigit() = let two = decimal 2 Seq.head (seq { for dd in [9..-1..0] do let zd = decimal dd * (decimal 10 ** -scale) let numberSqDiff = number * zd * two + zd * zd if numberSqDiff <= squareDifference then number <- number + zd squareDifference <- squareDifference - numberSqDiff scale <- scale + 1 yield dd }) // 数値ジェネレータークラス type NumbersGenerator() = let generator = let number = decimal 0 let squareDifference = decimal 3 let nums = Numbers(number, squareDifference, 0) seq { while true do yield nums.GetNextDecimalDigit() } member _.GetNextDecimalDigit() = generator |> Seq.head member _.GenerateDecimal() = generator // 数値サーバークラス type NumbersServer() = let mutable currentNumbers = Numbers(decimal 0, decimal 3, 0) let generatorServer = Seq.unfold (fun n -> Some(n, n)) currentNumbers member _.GetNumbers() = currentNumbers member _.SetNumbers(numbers: Numbers) = currentNumbers <- numbers // 計算クラス type Calc() = let count = 21 let generator = NumbersGenerator() let generatorServer = NumbersServer() let mutable resultNumber = decimal 0 member _.RepeatGenerator() = for e in [0 .. count - 1] do let zd = (decimal (generator.GetNextDecimalDigit())) / (10M ** e) resultNumber <- resultNumber + zd resultNumber.ToString() member _.RepeatServer() = for e in [0 .. count - 1] do let numbers = generatorServer.GetNumbers() let dd = numbers.GetNextDecimalDigit() generatorServer.SetNumbers(numbers) resultNumber <- resultNumber + (decimal dd) / (10M ** e) resultNumber.ToString() member _.IterateGenerator() = let dec = Seq.take count (generator.GenerateDecimal()) formatDecimal dec member _.IterateServer() = let initialNumbers = Numbers(decimal 0, decimal 3, 0) let dec = Seq.take count (Seq.unfold (fun (n: Numbers) -> let nn = n.Copy() in Some(nn.GetNextDecimalDigit(), nn)) initialNumbers) formatDecimal dec // テスト出力 printfn "%s" (Calc().RepeatGenerator()) printfn "%s" (Calc().RepeatServer()) printfn "%s" (Calc().IterateGenerator()) printfn "%s" (Calc().IterateServer())