# 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 は採用されない。