# 関数種別

すべての関数は 3 つの**種別**のいずれかを持ちます。種別は `fn` の前に書き、言語がコードにできることを制限するのはこの種別だけです。

```kis
fn open_config() { nav::call(Config) }                 // Turing-complete, runtime
#[scene] pushdown fn Confession() -> Answer { … }      // the story
const fn fade_in(mut screen: Screen) -> Screen { … }   // pure, compile time
```

| 種別 | 使えるもの | 評価 |
| ---- | ---------- | ---- |
| `fn` | 物語変数以外のすべて | 実行時 |
| `pushdown fn` | 実行時には[有限型](#finite-types)のみ、物語変数。ステップは `#[scene]` の中だけ | 実行時、物語の中で |
| `const fn` | すべての型。物語変数・設定値・メタ・シグナル・I/O は不可 | 必要な場所ではコンパイル時。実行時に呼ぶこともできる |

コンパイラが種別を推論することはありません。`const` と書いた関数だけが `const` です。

## 呼び出し規則 {#call-rules}

| 呼び出し元 ↓ / 呼び出し先 → | `fn` | `pushdown fn` | `const fn` |
| --------------------------- | ---- | ------------- | ---------- |
| `fn`                | 可 | 不可。[エントリーシーンの開始](./entry.md)だけができる | 可 |
| `pushdown fn`       | 不可 | 可 | 可。[後述](#calling-const-fn-from-the-story) |
| `const fn`          | 不可 | 不可 | 可 |

この表に反する呼び出しは `E3001` です。物語の中ではさらに[シーンと即時手続き](./scenes.md#scenes-and-instant-procedures)を分ける規則があり、ステップの実行（`E3002`）、別のシーンの呼び出し（`E3003`）、乱数の取得（`E3024`）は `#[scene]` だけができます。

関数ポインタやクロージャの型は種別を持つので、規則はそれらを通しても成り立ちます。`pushdown fn() -> R` 型の値は `pushdown fn` しか指せないため、物語がポインタ経由でチューリング完全なコードに到達することはありません（[値、参照、クロージャ](../syntax/values.md)を参照）。

種別ごとのまとめ：

| 種別 | 呼べるもの | 実行時に保持できるもの | ステップ | 物語変数 |
| ---- | ---------- | ---------------------- | -------- | -------- |
| `fn` | `fn`、`const fn`。エントリーシーンを開始できる | 何でも | 不可 | 不可 |
| `#[scene] pushdown fn` | シーン、即時手続き、`const fn`（定数または有限の引数） | 有限型 | 可 | 読み書き可 |
| `pushdown fn`（即時手続き） | 即時手続き、`const fn`。再帰不可、ループは `for` のみ | 有限型 | 不可 | 読み書き可 |
| `const fn` | `const fn` | 何でも | 不可 | 不可 |

## `pushdown fn` {#pushdown-fn}

`pushdown fn` は物語の一部です。次のことができます。

- [有限型](#finite-types)の値だけを受け取り、保持し、返す（`E3008`）。
- [物語変数](./story.md#story-variables)を読み書きする。
- 他の `pushdown fn` と `const fn` を呼ぶ。

`#[scene]` を付けた `pushdown fn` は**シーン**です。プレイヤーの入力まで物語を中断する[ステップ](./steps.md)を実行できるのも、自分自身を含む他のシーンを呼べるのもシーンだけです。シーン内のすべてのループと呼び出しの循環は、ステップを通らなければなりません（[停止性](./scenes.md#termination)を参照）。`#[scene]` のない `pushdown fn` は**即時手続き**です。ステップを実行せず、再帰せず、有界なループしか持たないため、入力なしに必ず終わります。どちらにしても、2 つの入力の間のコードは必ず終わります。

シーンは Kotlin の `suspend` 関数のように直接呼び合います。`.await` はありません。呼び出しの奥のどこかでステップに達すると物語全体が中断し、入力があると同じ地点から再開します。

## `const fn` {#const-fn}

`const fn` は純粋かつ決定的で、結果は引数だけで決まります。物語変数（`E3007`）、設定値、メタ（`E3013`）、シグナルは読めず、I/O もありません。内部はチューリング完全で、ループ、再帰、Rust の整数、`Rat`、`Decimal`、`String`、`Vec` を使えます。

コンパイラは、定数、[レンダー関数](./presentation.md)、物語からの呼び出しなど、結果がコンパイル時に必要な場合に `const fn` を評価します。評価には 1,000,000 評価ステップの固定予算があり（*暫定*：コンパイラ設定になる可能性があります）、使い切るとその値を必要とした呼び出しで `E4003` になります。`fn` のコードから実行時に呼んだ `const fn` は通常の関数呼び出しです。

### 物語から `const fn` を呼ぶ {#calling-const-fn-from-the-story}

`pushdown fn` は、すべての引数が[定数式](../syntax/constants.md)か有限型である場合に `const fn` を呼べます。

- **すべての引数が定数。** コンパイラは呼び出しをコンパイル時に評価し、その値で置き換えます（**畳み込み**）。値はどの型でも構いません。`fade(ms(500))` がこの例です。
- **一部の引数が有限型の実行時の値。** コンパイラは関数を**表化**します。呼び出しが受け取りうる引数の値のすべての組み合わせで関数を評価します。これは、ありうるすべての入力で呼び出しがエラーなく終わり、有限の結果を返すことのコンパイル時の証明です。プレイ中は、実際の引数で関数が普通に呼ばれます。結果は有限型でなければなりません（`E3008`）。引数の組み合わせが 65,536 を超える呼び出し（*暫定*：コンパイラ設定になる可能性があります）は `E4004` です。

```kix
const fn mood(affection: Int<0, 5>, met: bool) -> Mood {
    match (affection, met) {
        (4..=5, true) => Mood::Warm,
        (_, true) => Mood::Polite,
        _ => Mood::Stranger,
    }
}

#[scene]
pushdown fn Greeting() {
    match mood(AFFECTION_MIO, MET_MIO) {   // tabulated: 6 × 2 entries
        Mood::Warm => s!(t!["\"There you are!\""]),
        Mood::Polite => s!(t!["\"Hello.\""]),
        Mood::Stranger => s!(t!["\"…Who are you?\""]),
    }
}
```

書き手にとっては、物語の補助ロジックを `bool`、列挙型、`Int<lo, hi>` のような小さな有限の引数を持つ普通の `const fn` として書けばよい、ということです。関数内のエラー（オーバーフロー、ゼロ除算、終わらないループ）は、それを引き起こす引数の値についてコンパイル時に報告され、プレイ中に起きることはありません。

## `fn` {#fn}

普通の `fn` はチューリング完全な実行時コードで、ゲームシステム、その UI、セーブ、設定、メタを担います。`pushdown fn` を呼べず、物語変数も読めません。物語に入る唯一の方法は[エントリーシーンの開始](./entry.md)で、実行中の物語を見る唯一の手段は [`Narrative` ハンドル](./system.md)です。

## 有限型 {#finite-types}

`pushdown fn` のすべてのローカル変数、引数、戻り値、物語変数の型は有限でなければなりません。型が有限であるとは、値が有限個でコンパイラがそれを列挙できることです。

| 有限 | 有限でない |
| ---- | ---------- |
| `bool`、`()`、`!` | Rust の整数（`u8`、`i32` など）、`Rat`、`Decimal` |
| `Int<lo, hi>` | `String`、`Vec<T>` |
| ヴァリアントが有限なデータだけを持つ列挙型 | `Screen` などのビルトインのハンドル型 |
| 有限型の構造体、タプル、配列 `[T; N]` | 第一級のクロージャ |
| 有限な `T` の `Option<T>` | シグナル、設定値、メタの値 |
| `Text`（値はプログラム中の定数テキスト） | 自分自身を含む型（再帰型） |
| ファイルのアセット型 `ImageAsset`、`AudioAsset`、`VoiceAsset`、`VideoAsset`、`FontAsset`（値はプログラム中のアセット定数） | `EntityId`、`Part`、`Mark`、`Duration`、`Color`（Rust の整数を持つ）。`ColorShader<A>` などのシェーダー型 |
| `pushdown fn`、`scene fn`、`const fn` のポインタ（値はプログラム中の名前付き関数） | |
| 有限な `T` の `&T`、`&mut T`（引数として） | |

任意の型の定数式は、コンパイル時に畳み込まれるので `pushdown fn` の中にも書けます。標準ライブラリの型の完全な一覧は STD リファレンスの[std アイテムのコンパイラ規則](../../std/appendix/rules.md)にあります。

## なぜこれで成り立つのか {#why-this-works}

エンジンは物語に 2 つの性質を求めます。すべてのステップが終わること、そして「`MET_B` が false のままこのステップに到達できるか」のような問いにコンパイラが答えられることです。どちらも有限なデータ上のプッシュダウンシステムで成り立ち、種別は物語をちょうどそのようなものにします。

- **物語は閉じている。** `pushdown fn` が呼べるのは `pushdown fn` と `const fn` だけで、物語から呼ばれた `const fn` は定数に畳み込まれるか、表化されます。つまり、受け取りうるすべての入力で有限の結果を返して終わることが証明されます。
- **入口はエントリーだけ。** チューリング完全なコードが物語に入るのはエントリーシーンを開始するときだけで、その引数は有限で、セーブに記録され、解析はそのすべての値について成り立ちます。戻ってくるのはエントリーシーンの戻り値と、物語が書くだけで読まないメタだけです。
- **フレームは有限のまま。** スタックフレームは戻り先と有限なローカル変数を持ちます。物語の参照とクロージャは第二級なので、状態の一部になることはありません。
- **関数ポインタは有限。** 名前付き関数は有限個なので、ポインタは有限集合の値です。

こうしてシステムとプレゼンテーションは自由に計算できます。物語の解析はそれらに依存しません。背景は[哲学：構成による解析可能性](../overview/philosophy.md)にあります。
