Add associative map constraints and range refinement

This commit is contained in:
2026-08-14 06:26:15 +09:00
parent 8198b615a8
commit cc6ab40807
52 changed files with 8951 additions and 6918 deletions
+44 -3
View File
@@ -30,6 +30,7 @@
| `&` | `lhs & rhs` | composition | value / constraint / object | constraint-preserving composition |
| `//` | `lhs // rhs` | patch | object / value | right-biased structural patch |
| `default` | `base default fallback` | default | abstract value | materialization fallback |
| `as` | `narrower as wider` | range refinement | value / constraint / structure | narrower result plus untouched right-only ranges |
`concrete scalar``String``Bool``Int``Float` を指す。
@@ -48,6 +49,7 @@
9. `&`
10. `//`
11. `default`
12. `as`
同じ優先順位の二項演算子は左結合である。
`default` は右結合である。
@@ -91,6 +93,7 @@ A & B
- 両方が異なる具体値なら conflict になる。
- 両方が object なら、フィールドごとに合成する。
- 同じフィールドが両方にある場合、そのフィールド値を `&` で合成する。
- 片方にしかないフィールドは、そのまま結果に保持する。
- 矛盾が発生した場合はエラーになる。
例:
@@ -188,12 +191,44 @@ object field 全体を特別に置き換えるための `replace(...)` 構文や
object 全体を別構造にしたい場合は、patch 対象より外側で値を作り直す。
## `&` と `//` の使い分け
## `as`: range refinement
`&`制約を満たす具体化に使う
`as`左辺が右辺より具体的で狭い範囲であることを確認する、非対称な絞り込み演算子である
```dcdl
ValidConfig = MyConfig & {
Refined = {
port = 8000;
} as {
port = Int & >= 1 & <= 65535;
host = String;
enabled = Bool default true;
};
```
`port` は左辺の `8000` に具体化される。
右辺にしかない `host``enabled` は abstract のまま結果へ残る。default の有無は、右辺だけの field を保持するかどうかに影響しない。
`as` 自体は default を選択せず、後から結果を materialize した場合だけ通常の default 規則が働く。
左辺にしかない object field は右辺の field domain 外なのでエラーになる。
両側にある nested object、array constraint、map constraint は同じ規則で再帰的に絞り込む。
abstract range 同士も包含を確認できる。
```dcdl
Int & > 10 as Int & > 0 # 成功し、Int & > 10 を返す
Int as Int & > 0 # 失敗
```
`&` は対称な合成であり、片方だけにある object field を保持する。
したがって、左右に方向を持つ絞り込みを `&` で代用しない。
詳細は [Range Refinement](./expression/ascription.md) を参照する。
## `&`、`//`、`as` の使い分け
`&` は制約や部分構造を失わず、対称に合成する。
```dcdl
Combined = MyConfig & {
port = 8000;
};
```
@@ -208,3 +243,9 @@ ModifiedSchema = MyConfig // {
`//` は右辺優先の patch であり、左辺の制約を常に保持するとは限らない。
制約を保持したい場合は `&` を使う。
左辺が右辺より狭いことを検証しながら合成する場合は `as` を使う。
```dcdl
RefinedConfig = NarrowConfig as WideConfig;
```