79 lines
2.0 KiB
Markdown
79 lines
2.0 KiB
Markdown
# 遅延評価
|
|
|
|
この言語はフィールド単位で遅延評価する。
|
|
|
|
## 基本方針
|
|
|
|
```n
|
|
{
|
|
schema = {
|
|
hoge = String;
|
|
};
|
|
|
|
result = expensive(schema);
|
|
}
|
|
```
|
|
|
|
`schema` のみが必要な場合、`result` は評価されない。
|
|
|
|
## thunk
|
|
|
|
各フィールドや let 束縛は thunk として保持できる。
|
|
|
|
```text
|
|
Thunk {
|
|
expr: ExprId
|
|
env: EnvRef
|
|
state: Unevaluated | Evaluating | Evaluated(Value) | Error
|
|
}
|
|
```
|
|
|
|
評価済み thunk は memoize する。
|
|
同じフィールドを複数回参照しても、評価は一度だけでよい。
|
|
|
|
## 評価状態
|
|
|
|
thunk は以下の状態を持つ。
|
|
|
|
```text
|
|
Unevaluated 未評価
|
|
Evaluating 評価中
|
|
Evaluated 評価済み
|
|
Error 評価失敗
|
|
```
|
|
|
|
`Evaluating` の thunk を再度評価しようとした場合、循環依存として扱う。
|
|
|
|
## 循環検出
|
|
|
|
```n
|
|
{
|
|
a = b + 1;
|
|
b = a + 1;
|
|
}
|
|
```
|
|
|
|
この場合、`a` または `b` を評価すると循環エラーになる。
|
|
|
|
一方、同じモジュール内または import 間に循環があっても、評価対象のフィールドが循環していなければ成功する。
|
|
|
|
## 評価と materialize の分離
|
|
|
|
通常の評価では、制約や default を含む中間値が残ることがある。
|
|
外部へデータとして出力する段階で materialize を行う。
|
|
|
|
この分離により、以下が可能になる。
|
|
|
|
- スキーマを値として扱う。
|
|
- default を必要になるまで評価しない。
|
|
- import されたモジュールの未使用フィールドを評価しない。
|
|
- 制約だけのフィールドを中間状態として保持する。
|
|
|
|
## 関数呼び出しとの関係
|
|
|
|
関数引数は thunk として渡せる。
|
|
関数本体内で引数が参照されたときに評価する。
|
|
|
|
任意の関数呼び出し結果をグローバルに memoize することは必須ではない。
|
|
ただし、フィールドに束縛された呼び出し結果は、そのフィールド thunk の評価結果として memoize される。
|