3.2 KiB
3.2 KiB
Composition and Materialization
&、//、default、materialize は、runtime value の variant に基づいて処理する。
&
& は制約を保った合成である。
compose_and(a: RuntimeValue, b: RuntimeValue) -> RuntimeValue | Diagnostic
基本規則:
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 ごとに再帰合成する。
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 は同一候補として扱ってよい。
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 である。
patch(a: RuntimeValue, b: RuntimeValue) -> RuntimeValue
基本規則:
- object / object は field ごとに再帰 patch する。
- object / object 以外は右辺で置き換える。
- 左辺にしかない field は保持する。
- 右辺にしかない field は追加する。
- 配列、scalar、function は右辺置換とする。
// は制約を保持するための演算子ではない。
制約を満たす具体化には & を使う。
materialize
materialize は runtime value を出力可能な Data に変換する。
materialize(RuntimeValue) -> Data | Diagnostic
処理規則:
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 は採用されない。