Decodal/doc/manual/souce/design/composition-and-materialization.md

120 lines
3.2 KiB
Markdown

# Composition and Materialization
`&`、`//`、`default`、materialize は、runtime value の variant に基づいて処理する。
## `&`
`&` は制約を保った合成である。
```text
compose_and(a: RuntimeValue, b: RuntimeValue) -> RuntimeValue | Diagnostic
```
基本規則:
```text
Abstract(a) & Abstract(b)
-> Abstract {
constraints: a.constraints + b.constraints,
default: merge_default(a.default, b.default)
}
Abstract(a) & Concrete(v)
-> if satisfies(v, a.constraints) then Concrete(v)
else constraint diagnostic
Concrete(v) & Abstract(a)
-> if satisfies(v, a.constraints) then Concrete(v)
else constraint diagnostic
Concrete(Object(a)) & Concrete(Object(b))
-> Concrete(Object(fieldwise_and(a, b)))
Concrete(a) & Concrete(b)
-> if a == b then Concrete(a)
else conflict diagnostic
```
`Abstract & Concrete` が成功した場合、default は消える。
明示値があるなら fallback は不要だからである。
## object の合成
object は concrete structure だが、field の値は thunk 経由で concrete / abstract のどちらにもなりうる。
object 同士の `&` は field ごとに再帰合成する。
```dcdl
MyConfig = {
host = String;
port = Int default 8080;
};
Config = MyConfig & {
host = "localhost";
};
```
`host``Abstract(String) & Concrete("localhost")` として検証され、成功すれば `Concrete("localhost")` になる。
`port` は右辺に明示値がないため、`Abstract(Int, default 8080)` のまま残る。
## default の合成
初期方針では、`&` による異なる default 同士の合成は conflict とする。
同じ default は同一候補として扱ってよい。
```text
merge_default(None, None) -> None
merge_default(Some(a), None) -> Some(a)
merge_default(None, Some(b)) -> Some(b)
merge_default(Some(a), Some(b)) -> if same(a, b) then Some(a) else conflict
```
`//` では右辺 default が左辺 default を置き換える。
## `//`
`//` は右辺優先の deep patch である。
```text
patch(a: RuntimeValue, b: RuntimeValue) -> RuntimeValue
```
基本規則:
- object / object は field ごとに再帰 patch する。
- object / object 以外は右辺で置き換える。
- 左辺にしかない field は保持する。
- 右辺にしかない field は追加する。
- 配列、scalar、function は右辺置換とする。
`//` は制約を保持するための演算子ではない。
制約を満たす具体化には `&` を使う。
## materialize
materialize は runtime value を出力可能な `Data` に変換する。
```text
materialize(RuntimeValue) -> Data | Diagnostic
```
処理規則:
```text
Concrete(String/Int/Float/Bool) -> Data
Concrete(Array(items)) -> each item を force して materialize
Concrete(Object(fields)) -> each field を force して materialize
Concrete(Function) -> materialize 不能
Abstract { constraints, default: Some(d) }
-> force(d)
-> result が constraints を満たすか検証
-> materialize(result)
Abstract { constraints, default: None }
-> 未解決 abstract value として diagnostic
```
materialize は default を採用する唯一の段階である。
通常評価中に明示値が得られた場合、default は採用されない。