Decodal/doc/manual/souce/language/evaluation.md
2026-06-16 00:45:10 +09:00

2.0 KiB

遅延評価

この言語はフィールド単位で遅延評価する。

基本方針

{
    schema = {
        hoge = String;
    };

    result = expensive(schema);
}

schema のみが必要な場合、result は評価されない。

thunk

各フィールドや let 束縛は thunk として保持できる。

Thunk {
  expr: ExprId
  env: EnvRef
  state: Unevaluated | Evaluating | Evaluated(Value) | Error
}

評価済み thunk は memoize する。 同じフィールドを複数回参照しても、評価は一度だけでよい。

評価状態

thunk は以下の状態を持つ。

Unevaluated  未評価
Evaluating   評価中
Evaluated    評価済み
Error        評価失敗

Evaluating の thunk を再度評価しようとした場合、循環依存として扱う。

循環検出

{
    a = b + 1;
    b = a + 1;
}

この場合、a または b を評価すると循環エラーになる。

一方、同じモジュール内または import 間に循環があっても、評価対象のフィールドが循環していなければ成功する。

評価と materialize の分離

通常の評価では、制約や default を含む中間値が残ることがある。 外部へデータとして出力する段階で materialize を行う。

この分離により、以下が可能になる。

  • スキーマを値として扱う。
  • default を必要になるまで評価しない。
  • import されたモジュールの未使用フィールドを評価しない。
  • 制約だけのフィールドを中間状態として保持する。

関数呼び出しとの関係

関数引数は thunk として渡せる。 関数本体内で引数が参照されたときに評価する。

任意の関数呼び出し結果をグローバルに memoize することは必須ではない。 ただし、フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。