細化類型

badge

細化類型是受謂詞表達式約束的類型。枚舉類型和區間類型是細化類型的語法糖

細化類型的標準形式是{Elem: Type | (Pred)*}。這意味著該類型是其元素為滿足 PredElem 的類型 可用于篩選類型的類型僅為 數值類型

Nat = 0.. _
Odd = {N: Int | N % 2 == 1}
Char = StrWithLen 1
# StrWithLen 1 == {_: StrWithLen N | N == 1}
[Int; 3] == {_: Array Int, N | N == 3}
Array3OrMore == {A: Array _, N | N >= 3}

當有多個 pred 時,可以用 ;andor 分隔。;and 的意思是一樣的

Odd 的元素是 1, 3, 5, 7, 9, ... 它被稱為細化類型,因為它的元素是現有類型的一部分,就好像它是細化一樣

Pred 被稱為(左側)謂詞表達式。和賦值表達式一樣,它不返回有意義的值,左側只能放置一個模式 也就是說,諸如X**2 - 5X + 6 == 0之類的表達式不能用作細化類型的謂詞表達式。在這方面,它不同于右側的謂詞表達式

{X: Int | X**2 - 5X + 6 == 0} # 語法錯誤: 謂詞形式無效。只有名字可以在左邊

如果你知道如何解二次方程,你會期望上面的細化形式等價于{2, 3} 但是,Erg 編譯器對代數的了解很少,因此無法解決右邊的謂詞

智能投射

很高興您定義了 Odd,但事實上,它看起來不能在文字之外使用太多。要將普通 Int 對象中的奇數提升為 Odd,即將 Int 向下轉換為 Odd,您需要傳遞 Odd 的構造函數 對于細化類型,普通構造函數 .new 可能會出現恐慌,并且有一個名為 .try_new 的輔助構造函數返回一個 Result 類型

i = Odd.new (0..10).sample!()
i: Odd # or Panic

它也可以用作 match 中的類型說明

# i: 0..10
i = (0..10).sample!
match i:
    o: Odd ->
        log "i: Odd"
    n: Nat -> # 0..10 < Nat
        log "i: Nat"

但是,Erg 目前無法做出諸如"偶數"之類的子決策,因為它不是"奇數"等

枚舉、區間和篩選類型

前面介紹的枚舉/區間類型是細化類型的語法糖 {a, b, ...}{I: Typeof(a) | I == a 或 I == b 或 ... },并且 a..b 被去糖化為 {I: Typeof(a) | 我 >= a 和我 <= b}

{1, 2} == {I: Int | I == 1 or I == 2}
1..10 == {I: Int | I >= 1 and I <= 10}
1... <10 == {I: Int | I >= 1 and I < 10}

細化模式

正如 _: {X} 可以重寫為 X(常量模式),_: {X: T | Pred} 可以重寫為X: T | Pred

# 方法 `.m` 是為長度為 3 或更大的數組定義的
Array(T, N | N >= 3)
    .m(&self) = ...