Document implementation design
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
# 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 は採用されない。
|
||||
Reference in New Issue
Block a user