5.4 KiB
Erg design's "Why" and Answers
为什么有产权体系,GC 也让它共存?
因为 Erg 推出所有权系统的动机并不是为了 Rust 那样的“不依赖 GC 的内存管理”。最初,由于 Erg 是一种语言,目前已被 Python 字节码删除,因此最终仍使用 GC。Erg 引入产权系统的目标是“可变状态的局部化”。在 Erg 中,可变对象具有所有权概念。这是根据共享可变状态容易成为 bug 的温床,甚至是类型安全性的侵犯(详见)来判断的。
为什么类型参数周围的括号不是 <> 或 []?
因为在和<gtr=“7”/>中会发生语法冲突。
# []版
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 等环境中为 {i:Int}。为什么 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はFile型
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,并且原则上禁止多重和多层继承,因此继承的使用相对安全。
为什么多相关数的子类型推理默认指向记名特雷特?
默认情况下,指向结构托盘会使类型指定变得复杂,并且可能会混合程序员的非预期行为。
# If T is a subtype of a structural trait...
# f: |T <: Structural Trait {.`_+_` = Self.(Self) -> Self; .`_-_` = Self.(Self) -> Self}| (T, T) -> T
f|T| x, y: T = x + y - x
# T is a subtype of a nominal trait
# 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 试图用类来控制一切一样。