Files
Decodal/doc/manual/souce/language/expression/ascription.md
T

3.1 KiB

Range Refinement

narrower as wider は、左辺が右辺より具体的で狭い範囲であることを確認し、両者を非対称に合成する演算である。

Int & > 10 as Int & > 0

この例は成功し、結果は左辺の狭い範囲 Int & > 10 のままになる。逆向きの Int as Int & > 0 は、左辺が右辺を満たすとは限らないため失敗する。

Object

object では、右辺を field domain として左辺の field を確認する。

  • 左辺にしかない field は、右辺の domain 外なのでエラーになる。
  • 両側にある field は、左辺が右辺より狭いかを再帰的に確認し、左辺の狭い結果を使う。
  • 右辺にしかない field は、default の有無に関係なく未評価のまま結果へ残す。
  • 結果の field order は右辺の順序に従う。
partial = {
    port = 8080;
} as {
    host = String;
    port = Int;
    enabled = Bool default true;
};

partial.port8080 に具体化される。partial.hostpartial.enabled は右辺由来の abstract field のままであり、asenabled の default を選択も force もしない。

その後 partial 全体を materialize すれば、通常の materialize 規則が適用される。この例では unresolved な host がエラーになり、host も具体化されていれば enabled の default がその時点で利用される。

Default

default は範囲包含の根拠ではない。両側に同じ field がある場合、結果には左辺を使うため、右辺の default を左辺へ注入しない。

Int & > 0 as (Int default 1)

結果は default のない Int & > 0 である。一方、右辺だけに残る object field は field 全体を保持するため、その abstract value が元から持つ default も保持される。

Map and array ranges

{...T} は任意の object key を許可し、各 value が T より狭いことを確認する。

ports = {
    http = 80;
    https = 443;
} as {...(Int & >= 1 & <= 65535)};

[...T] を右辺に使う場合も、すべての array element を T に対して絞り込む。

Concrete right-hand ranges

primitive constraint や合成 constraint は通常どおり値を検証する。 右辺が concrete scalar または array literal の場合は、左辺も同じ値または同じ長さ・要素構造である必要がある。 function は右辺の範囲として使用できない。

左辺は concrete value に限らない。包含関係を判定できる constraint 同士であれば abstract value も使用できる。primitive type、numeric bound、同一 regex / predicate、array/map の要素範囲は包含確認の対象になる。

関数 parameter の name: range も、引数が force された時点で as と同じ絞り込み規則を使う。

Precedence

asdefault より低い、最も低い優先順位を持ち、左結合である。

narrow & overrides as Wider

これは (narrow & overrides) as Wider と解釈される。