非専門的シンギュラリティー研究所

無限に動き続けるシステムを表す方法を AI なども使って考えていきます。

関数プログラミングの帰納的関数(6)

F# の無限列を生成する関数を、無限列の各要素を取得する関数の列と見ると、帰納的関数といえるかどうか ChatGPT で調べてみました。

F# でフィボナッチ数列の無限列を生成する関数を、無名関数を返して終了する関数として定義してください

と入力すると以下の結果となりました。

F# でフィボナッチ数列の無限列を生成し、無名関数を返す関数を定義するには、遅延評価を活用する必要があります。以下のコードでは、無名関数が次のフィボナッチ数を計算し続ける形で動作します。

let fibonacciGenerator () =
    let rec nextFib a b = fun () -> a, nextFib b (a + b)
    nextFib 0 1

let fibSeq = fibonacciGenerator ()

let first10 = List.init 10 (fun _ -> let x, next = fibSeq() in x, next)

// フィボナッチ数列の最初の10個を取得
let values = first10 |> List.map fst

printfn "%A" values

説明:

1. `fibonacciGenerator` は無名関数 `fun () -> a, nextFib b (a + b)` を返す。
2. `nextFib` は `(a, b)` の現在の値を保持し、呼び出されるたびに次の値を生成する無名関数を返す。
3. `fibSeq` は `fibonacciGenerator()` によって最初の状態を持つクロージャを作成する。
4. `fibSeq()` を呼び出すたびに、次のフィボナッチ数と新しい無名関数が得られる。

これにより、関数を呼び出すたびに次のフィボナッチ数が生成される無限列を表現できます。

fibonacciGenerator は「μ-帰納的関数」の意味の「帰納的関数」ですか

と入力すると以下の結果となりました。

「μ-帰納的関数(μ-recursive function)」の意味で `fibonacciGenerator` が帰納的関数かどうかを考えてみましょう。

μ-帰納的関数とは?

計算理論における μ-帰納的関数(μ-recursive function) は、次の 3 つの基本的な操作から構成される関数のクラスです:

1. 零関数(Zero function): 定数関数  Z(x) = 0 など
2. 後者関数(Successor function):  S(x) = x + 1
3. 射影関数(Projection function): 入力の特定の成分を取り出す関数

これらの基本関数から、次の操作を用いてより複雑な関数を構成できます:

  • 原始再帰(Primitive Recursion): 基本ケースと再帰的ステップで関数を構成
  • μ-作用素(Minimization Operator, μ-Operator): ある条件を満たす最小の自然数を求める操作

`fibonacciGenerator` は μ-帰納的関数か?

`fibonacciGenerator` は 関数を返す高階関数 であり、自然数を入力として値を返す「通常の関数」ではありません。そのため、μ-帰納的関数として厳密に定義するのは難しいですが、考え方を整理すると次のようになります。

1. フィボナッチ数列の定義
フィボナッチ数列自体は、次のような 原始再帰関数(primitive recursive function) で定義できます:
\displaystyle
   F(0) = 0, \quad F(1) = 1
\displaystyle
   F(n) = F(n-1) + F(n-2) \quad (n \geq 2)
これは 原始再帰的関数 であり、μ-帰納的関数の一部です。

2. `fibonacciGenerator` の構造
`fibonacciGenerator` は フィボナッチ数列を無限に生成する関数を返す」 ため、通常の μ-帰納的関数の形式には当てはまりません。μ-帰納的関数自然数を入力にとり、自然数を出力する関数であるため、「高階関数(関数を返す関数)」という性質は通常の枠組みには入りません。

3. 帰納的定義の観点

  • `fibonacciGenerator` の内部には 帰納的に定義された無名関数 `nextFib` が含まれています。
  • しかし、μ-帰納的関数として厳密に扱うには、単純な数値の計算に落とし込む必要があります。
  • そのため、`fibonacciGenerator` 自体は μ-帰納的関数とは言えませんが、その動作原理の一部(フィボナッチ数列の計算)は 原始再帰的関数として μ-帰納的関数に含まれる 可能性があります。

結論

つまり、「フィボナッチ数列の各値を計算する関数」は μ-帰納的関数になり得ますが、`fibonacciGenerator` のように「無限列を生成する高階関数」は、μ-帰納的関数の範疇ではありません。

fibonacciGenerator の定義を変更して「μ-帰納的関数」として定義することはできませんか

と入力すると以下の結果となりました。

`fibonacciGenerator` を μ-帰納的関数として定義できるか?

μ-帰納的関数(μ-recursive function)の枠組みでは、 自然数を入力にとり、自然数を出力する関数 のみが許されます。そのため、無限列を直接表現する高階関数 `fibonacciGenerator` の形では μ-帰納的関数としては扱えません。

しかし、フィボナッチ数列の各項を計算する関数を μ-帰納的関数として定義することは可能 です。つまり、 「n 番目のフィボナッチ数を求める関数」 を μ-帰納的関数として書き直すことができます。

μ-帰納的関数としてのフィボナッチ数列

フィボナッチ数列  F(n) は以下の原始再帰(primitive recursion)で定義されます:
\displaystyle
F(0) = 0, \quad F(1) = 1
\displaystyle
F(n) = F(n-1) + F(n-2) \quad (n \geq 2)
この形であれば、原始再帰的関数(primitive recursive function) の範囲に収まり、μ-帰納的関数の一種になります。

F# でこの形にした場合、以下のようになります:

let rec fibonacci n =
    if n = 0 then 0
    elif n = 1 then 1
    else fibonacci (n - 1) + fibonacci (n - 2)

これは μ-帰納的関数 の定義の枠組みに収まります。

「無限列」を μ-帰納的関数の範囲で扱うには?

本来、μ-帰納的関数は「無限列」そのものを直接表現できません。しかし、無限列の各項を個別に計算する関数 を考えれば、それを μ-帰納的関数として定義できます。
例えば、以下のように 「n 番目のフィボナッチ数を求める関数」 を μ-帰納的関数にすることで、間接的に無限列を表現できます。

let fibonacciGenerator n = fibonacci n

この関数 `fibonacciGenerator` は、 自然数 n を受け取り、n 番目のフィボナッチ数を返す ため、μ-帰納的関数の定義に適合します。

結論

  • `fibonacciGenerator` を 「n 番目のフィボナッチ数を求める関数」 に変更すれば、μ-帰納的関数として定義できる。
  • 無限列そのものを μ-帰納的関数として直接定義することはできない。
  • 「n 番目の値を計算する関数」に帰着させることで μ-帰納的関数の枠組みに収めることが可能。