Widening
例如,定義多相關系數如下
ids|T|(x: T, y: T) = x, y
分配同一類的一對實例并沒有錯 當您分配另一個具有包含關系的類的實例對時,它會向上轉換為較大的類并成為相同的類型 另外,很容易理解,如果分配了另一個不在包含關系中的類,就會發生錯誤
assert ids(1, 2) == (1, 2)
assert ids(1, 2.0) == (1.0, 2.0)
ids(1, "a") # TypeError
現在,具有不同派生類型的類型呢?
i: Int or Str
j: Int or NoneType
ids(i, j) # ?
在解釋這一點之前,我們必須關注 Erg 的類型系統實際上并不關注(運行時)類這一事實
1: {__valueclass_tag__ = Phantom Int}
2: {__valueclass_tag__ = Phantom Int}
2.0: {__valueclass_tag__ = Phantom Ratio}
"a": {__valueclass_tag__ = Phantom Str}
ids(1, 2): {__valueclass_tag__ = Phantom Int} and {__valueclass_tag__ = Phantom Int} == {__valueclass_tag__ = Phantom Int}
ids(1, 2.0): {__valueclass_tag__ = Phantom Int} and {__valueclass_tag__ = Phantom Ratio} == {__valueclass_tag__ = Phantom Ratio} # Int < Ratio
ids(1, "a"): {__valueclass_tag__ = Phantom Int} and {__valueclass_tag__ = Phantom Str} == Never # 類型錯誤
我看不到該類,因為它可能無法準確看到,因為在 Erg 中,對象的類屬于運行時信息
例如,一個Int
或Str類型的對象的類是
Int或
Str,但你只有通過執行才能知道它是哪一個 當然,
Int類型的對象的類被定義為
Int,但是在這種情況下,從類型系統中可見的是
Int的結構類型
{valueclass_tag = Int}`
現在讓我們回到另一個結構化類型示例。總之,上述代碼將導致類型錯誤,因為類型不匹配 但是,如果您使用類型注釋進行類型擴展,編譯將通過
i: Int or Str
j: Int or NoneType
ids(i, j) # 類型錯誤: i 和 j 的類型不匹配
# 提示: 嘗試擴大類型(例如 ids<Int or Str or NoneType>)
ids<Int or Str or NoneType>(i, j) # OK
A 和 B
有以下可能性
A and B == A
: 當A <: B
或A == B
時A and B == B
: 當A :> B
或A == B
時A and B == {}
: 當!(A :> B)
和!(A <: B)
時
A 或 B
具有以下可能性
A 或 B == A
: 當A :> B
或A == B
時A or B == B
: 當A <: B
或A == B
時A 或 B
是不可約的(獨立類型): 如果!(A :> B)
和!(A <: B)
子程序定義中的類型擴展
如果返回類型不匹配,Erg 默認會出錯
parse_to_int s: Str =
if not s.is_numeric():
do parse_to_int::return error("not numeric")
... # 返回 Int 對象
# 類型錯誤: 返回值類型不匹配
# 3 | 做 parse_to_int::return error("not numeric")
# └─ Error
# 4 | ...
# └ Int
為了解決這個問題,需要將返回類型顯式指定為 Or 類型
parse_to_int(s: Str): Int or Error =
if not s.is_numeric():
do parse_to_int::return error("not numeric")
... # 返回 Int 對象
這是設計使然,這樣您就不會無意中將子例程的返回類型與另一種類型混合
但是,如果返回值類型選項是具有包含關系的類型,例如 Int
或 Nat
,它將與較大的對齊。