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

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

人工知能的サーバー対ブラウザー(4)

前回のサンプルは、「ユーザーの入力をサーバーのプログラムに反映させるにはどうするか」というものでした。以前のこのブログで、これを変数が変更可能なプログラミング言語で書いたものを、変数が変更不可能なものに書き換えるということをやっていました。

ユーザーがアクセスするごとに新しいバージョンのプログラムにアクセスするようになっているとします。

ユーザーからの1回目のアクセスはバージョン1
ユーザーからの2回目のアクセスはバージョン2
……

こうなっているとして、バージョン∞を考えます。これはバージョン1、バージョン2、…をすべて含むものとします。このバージョン∞はユーザーが実行していることをサーバーで実行することになるのではないか、ということを調べています。

バージョン∞をどう表せば良いかという問題を考えるために、変数が変更不可能とすれば考えやすくなるのではないか(たとえば形式的べき級数に対応させやすいのではないか)ということで、「ユーザーの入力をサーバーのプログラムに反映させるにはとうするか」は漠然としていては難しいので、まず「変数の変更可能なものを変更不可能に変更するとどうなるか」を調べています。

以前のこのブログでは TypeScript、F#、Go に書き換えています(「関数プログラミングと無限論理多項式」)。TypeScript、F# は Visual Studio ですぐ使えます。Go は Visual Studio Code から使えるようにしてありましたが、たぶん簡単にインストールできるからやってみたと思われます。他のプログラミング言語はインストールしてあるものもありましたが Visual Studio Code から使えるようにしてはいなかったので、簡単にできそうにないのでやめたのかもしれません。今はもうわかりません。

「ユーザーの入力をサーバーのプログラムに反映させるにはどうするか」ではなく「変数の変更可能なものを変更不可能に変更するとどうなるか」のサンプルとしては RepeatGenerator() だけで良いので、ここではそれをやってみます。Calc クラスは GUI から使うために処理をまとめたクラスなので GUI を使わないときは不要といえば不要です。

これは、クロージャーが使えて、変数の変更可能、変更不可能が指定できるプログラミング言語であれば良いので、他のプログラミング言語でもできればやってみます。これは、ブラウザー側のプログラミング言語の調査も兼ねています。

Lisp についても調査していますが、これは上記のことに付け加えて、「クロージャーが使えて、変数の変更可能、変更不可能が指定できるプログラミング言語」を Lisp の構文で書けないかをおそらく調べています(実際にはやっていないようなのでよくわかりません)。LOGO についても調査しようとしているようですが、これも同様と思われます(まだやっていないのでよくわかりません)。その後独自のプログラミング言語を作っている(「ラムダ計算と無限ラムダ多項式」)ので Lisp では(おそらく)何もしていません。

以上の理由で今回は ChatGPT で RepeatGenerator() を実行する部分だけを書き換えてもらいました。

{-# LANGUAGE DeriveFunctor #-}

import Data.Decimal
import Control.Monad (forM_)

-- Numbers データ型
data Numbers = Numbers
  { number :: Decimal
  , squareDifference :: Decimal
  , scale :: Int
  } deriving (Show)

-- 数字を作成するためのコピー
copy :: Numbers -> Numbers
copy nums = Numbers (number nums) (squareDifference nums) (scale nums)

-- 次の10進数桁を取得する関数
getNextDecimalDigit :: Numbers -> (Int, Numbers)
getNextDecimalDigit nums = go 9 nums
  where
    go dd n
      | dd < 0 = (0, n)
      | otherwise =
          let zd = fromIntegral dd `scaleB` (-scale n)
              two = Decimal 2 0
              numberSqDiff = number n * zd * two + zd * zd
           in if numberSqDiff <= squareDifference n
                 then (dd, Numbers (number n + zd) (squareDifference n - numberSqDiff) (scale n + 1))
                 else go (dd - 1) n

-- NumbersGenerator データ型
data NumbersGenerator = NumbersGenerator
  { nums :: Numbers
  } deriving (Show)

-- NumbersGenerator のインスタンス生成
createGenerator :: NumbersGenerator
createGenerator = NumbersGenerator (Numbers (Decimal 0 0) (Decimal 3 0) 0)

-- 次の10進数桁を取得する関数
getNextDecimalDigitGen :: NumbersGenerator -> (Int, NumbersGenerator)
getNextDecimalDigitGen generator =
  let (digit, newNums) = getNextDecimalDigit (nums generator)
   in (digit, generator { nums = newNums })

-- メイン関数
main :: IO ()
main = do
  let count = 21
      generator = createGenerator
  let (result, _) = foldl
        (\(resultNum, gen) e ->
           let (digit, newGen) = getNextDecimalDigitGen gen
               zd = fromIntegral digit `scaleB` (-e)
           in (resultNum + zd, newGen))
        (Decimal 0 0, generator)
        [0..count - 1]
  print result