Files
Decodal/doc/manual/source/jp/language/constraints-and-defaults.md
T

4.6 KiB

制約と default

constraint は、値が満たすべき範囲を表す。

Int
String
>= 1
<= 65535
/Hello! .*/

constraint は & で合成できる。

Port = Int & >= 1 & <= 65535;
NarrowedPort = Port & > 443;

合成結果は両辺を同時に満たす範囲になる。 両立しない constraint は conflict になる。

Int & String       # conflict
> 10 & < 5         # conflict
Int & > 10 & < 11  # conflict: integer candidate does not exist

Primitive and comparison constraints

組み込みの primitive range は次の通りである。

String
Int
Float
Bool

異なる primitive type を & で合成すると conflict になる。 数値比較 constraint は上下限として合成され、空の範囲になる場合は conflict になる。

Int & >= 1 & <= 65535 & > 443

Int の比較 constraint は integer literal を使う。 Float の比較 constraint は integer または float literal を使える。

Unknown

Unknown はすべての Decodal value を含む最上位 range である。 検査を無効化して具体値の情報を消す Any ではなく、値の範囲がまだ絞られていないことを表す。

Int & Unknown       # Int
42 as Unknown       # 42
Unknown as Int      # conflict

Unknown 自体は concrete value を持たないため materialize できない。 concrete value で絞り込むか default を指定する必要がある。

Unknown default {}

Regex constraints

regex literal は string constraint である。

Host = /^api-[0-9]+$/;

複数の regex constraint を合成した場合、concrete string はすべてに一致する必要がある。

String & /^a/ & /z$/

regex constraint 同士の交差は合成時には判定されない。 そのため、次の範囲は合成時には conflict にならず、concrete value の検証時に失敗する。

String & /^a$/ & /^b$/

Rust runtime では regex engine を regex feature で有効にする。 feature が無効な場合、regex constraint の concrete value 検証は unsupported feature diagnostic になる。

Array constraints

array constraint は [...T] と書き、すべての要素へ T を適用する。 要素 constraint は必須である。

Names = [...String];
PositiveInts = [...(Int & > 0)];

concrete array と合成した場合、各要素は T に対して as と同じ規則で絞り込まれる。 空 array は任意の array constraint を満たす。

要素 constraint が object range の場合、右辺にだけある field は abstract のまま各要素へ残る。 左辺にしかない field は右辺の field domain 外なので conflict になる。

Associative-array and object rest constraints

associative-array constraint は {...T} と書き、object の任意の field value へ T を適用する。

Services = {...{
    port = Int;
    enabled = Bool default true;
}};

key は列挙されず、空 object も許容される。 named field を持つ object の末尾へ ...T を書くと、列挙されていない field だけに T を適用できる。

{
    enabled = Bool default true;
    ...Unknown
}

rest constraint は field を生成しない。 実在する追加 field の検証にだけ使われる。

default

default は constraint ではない。 materialize 時に concrete value がない場合だけ使われる fallback である。

Port = Int & >= 1 & <= 65535;

Service = {
    port = Port default 8080;
};

明示値が合成された場合は明示値が使われ、default は評価されない。

Config = {
    port = 9000;
} as Service;

明示値がない場合、materialize 時に 8080 が採用され、Port を満たすか検証される。

default composition

  • & で片方だけが default を持つ場合、その default は保持される。
  • & で両辺が異なる default を持つ場合は conflict になる。
  • constraint と concrete value の & が成功した場合、結果は concrete value になり default は残らない。
  • // は右辺優先なので、同じ field では右辺の値または default が左辺を置き換える。
  • as は右辺の default を左辺へ注入しない。ただし右辺にだけ存在する field は、その field が持つ default とともに abstract なまま結果へ残る。

default expression は materialize 時に必要になった時点で評価され、同じ range の constraint を満たす必要がある。