erg/doc/zh_TW/dev_guide/faq_syntax.md
2022-09-06 20:13:44 +08:00

5.9 KiB
Raw Blame History

Erg design's "Why" and Answers

badge

當我們有所有權系統時,為什么要與 GC 共存?

因為 Erg 推出所有權系統的動機并不是為了 Rust 那樣的“不依賴 GC 的內存管理”。最初,由于 Erg 是一種語言,目前使用 Python VM因此最終仍使用 GC。Erg 引入產權系統的目標是“可變狀態的局部化”。在 Erg 中,可變對象具有所有權概念。這是根據共享可變狀態容易成為 bug 的溫床,甚至是類型安全性的侵犯(詳見)來判斷的。

為什么類型參數周圍的括號不是 <> 或 []

因為在和中會發生語法沖突。

# []版
id[T: Type] [t]: [T] = t
y = id[Int] # 這是一個功能嗎?
# <>版
id<T: Type> {t: T} = t
y = (id<Int, 1> 1) # 這是一個元組嗎?
# {}版
id{T: Type} {t: T} = t
y = id{Int} # 這是一個功能嗎?
# ||版
id|T: Type| t: T = t
y = id|Int| # OK

{i=1} 的類型為 {i=Int},但在 OCaml 等環境中為 {iInt}。為什么 Erg 采用前者的語法?

Erg 設計為將類型本身也視為值。

A = [Int; 3]
assert A[2] == Int
T = (Int, Str)
assert T.1 == Str
D = {Int: Str}
assert D[Int] == Str
S = {.i = Int}
assert S.i == Int

你打算在 Erg 中實現宏嗎?

目前沒有。宏觀大致分為四個目的。第一個是編譯時計算。這在 Erg 中由編譯時函數負責。第二,代碼執行的延遲。這可以用 do 塊來代替。第三個是處理通用化,對此多相關數和全稱類型是比宏觀更好的解決方案。第四個是自動生成代碼,但這會造成可讀性的下降,所以我們不敢在 Erg 中實現。因此,宏的大部分功能都由 Erg 型系統承擔,因此沒有動力進行部署。

為什么 Erg 沒有例外機制?

在許多情況下,錯誤處理類型是更好的解決方案。類型<gtr=“9”/>是一種錯誤處理方法,通常在較新的編程語言中使用。

在 Erg 中,運算符使你可以在不太注意錯誤的情況下編寫。

read_file!() =
    f = open!("foo.txt")? # 如果失敗則立即返回錯誤,所以 f 是文件類型
    f.read_all!()

# 也可以使用 try 過程捕獲類似的異常
try!:
    do!
        s = read_file!()?
        print! s
    e =>
        # 發生錯誤時執行的塊
        print! e
        exit 1

在引入 Python 函數時,缺省情況下,所有函數都被視為包含異常,返回類型為。如果你知道不調度異常,請在<gtr=“12”/>中指明。

此外Erg 沒有引入異常機制的另一個原因是它計劃引入并行編程的功能。這是因為異常機制與并行執行不兼容(例如,如果并行執行導致多個異常,則很難處理)。

Erg 似乎消除了 Python 被認為是壞做法的功能,但為什么沒有取消繼承?

Python 的庫中有一些類設計為繼承,如果完全取消繼承,這些操作就會出現問題。然而,由于 Erg 的類默認為 final并且原則上禁止多重和多層繼承因此繼承的使用相對安全。

為什么多相關數的子類型推理默認指向記名trait

默認情況下,指向結構托盤會使類型指定變得復雜,并且可能會混合程序員的非預期行為。

# 如果 T 是結構特征的子類型...
# f: |T <: Structural Trait {.`_+_` = Self.(Self) -> Self; .`_-_` = Self.(Self) -> Self}| (T, T) -> T
f|T| x, y: T = x + y - x
# T 是名義特征的子類型
# g: |T <: Add() and Sub()| (T, T) -> T
g|T| x, y: T = x + y - x

Erg 是否實現了定義自己的運算符的功能?

A沒有那個計劃。最重要的原因是如果允許定義自己的運算符就會出現如何處理組合順序的問題。可以定義自己的運算符的 Scala 和 Haskell 等都有不同的對應,但這可以看作是可能產生解釋差異的語法的證據。此外,獨立運算符還有一個缺點,那就是可能產生可讀性較低的代碼。

為什么 Erg 取消了 += 這樣的擴展賦值運算符?

首先Erg 中沒有變量的可變性。也就是不能重新賦值。一旦對象與一個變量關聯,它將一直綁定到該變量,直到它脫離作用域并被釋放。在 Erg 中,可變性是指對象的可變性。明白了這個,故事就簡單了。例如,表示<gtr=“14”/>,但由于變量是不可重新賦值的,因此這種語法是非法的。還有一個 Erg 的設計原則是運算符沒有副作用。Python 通常也是如此,但對于某些對象(如 Dict),擴展賦值運算符會更改對象的內部狀態。這算不上是一個很漂亮的設計。因此,擴展賦值運算符被完全廢棄。

為什么 Erg 在語法上特別對待有副作用的過程?

副作用的局部化是代碼維護的一個關鍵因素。

但是,確實也不是沒有方法可以不在語言上特殊對待副作用。例如,可以用代數效果(類型系統上的功能)替代過程。但這樣的合一并不總是正確的。例如Haskell 沒有對字符串進行特殊處理,只是一個字符數組,但這種抽象是錯誤的。

什么情況下可以說合一化是錯的一個指標是“是否會因其合一而難以看到錯誤信息”。Erg 設計師發現,將副作用特殊處理會使錯誤消息更容易閱讀。

Erg 有一個強大的類型系統,但并不是所有的類型都決定了它。如果這樣做了,你的下場就跟 Java 試圖用類來控制一切一樣。