mirror of
https://github.com/erg-lang/erg.git
synced 2025-08-04 18:58:30 +00:00
trifle
This commit is contained in:
parent
df77181e23
commit
a9ea4eca75
137 changed files with 355 additions and 351 deletions
|
@ -2,14 +2,15 @@
|
|||
|
||||
## Erg memory management model
|
||||
|
||||
Use ownership in CPython backend + Python memory management model (though circular references in Erg code will not be handled by GC [see details](../syntax/18_ownership.md/#circular references))
|
||||
Use ownership in CPython backend + Python memory management model (though circular references in Erg code will not be handled by GC [see details](../syntax/18_ownership.md/#circular-references)
|
||||
|
||||
Using ownership + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf) memory in Erg's own virtual machine (Dyne) Management model, if Erg code uses the Python API then the Erg code uses the tracking garbage collection memory management model
|
||||
|
||||
In LLVM, WASM backend uses ownership + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf) memory management model
|
||||
|
||||
Regardless of the backend, the difference in memory management will not need any changes to the code
|
||||
|
||||
__Notice__:Erg's motivation for introducing an ownership system is not for "memory management without relying on GC" like Rust.
|
||||
In the first place, Erg is currently a language that is reduced to Python bytecode, so GC is used after all.
|
||||
The aim of Erg's ownership system is ``localization of mutable state''. Erg has a notion of ownership attached to mutable objects.
|
||||
This is because shared mutable state is prone to bugs and even violates type safety (see [here](../syntax/type/advanced/shared.md#SharedReference)). It's a judgmental decision.
|
||||
|
||||
|
|
|
@ -95,9 +95,9 @@ Regarding the definition of rank, types that are not quantified, such as `Int`,
|
|||
R0 = (Int or Str or Bool or ...) or (R0 -> R0) or K(R0)
|
||||
```
|
||||
|
||||
Next, types with first-order universal quantification, such as `|T| T -> T`, or types that include them in the return value type are “rank 1”.
|
||||
In addition, types with second-order universal quantification (types that have rank 1 types as arguments such as `(|T| T -> T) -> Int`) or types that include them in the return type are called "rank 2 ”.
|
||||
The above is repeated to define the “Rank N” type. Also, the rank-N types include all types with a rank of N or less. Therefore, a type with mixed ranks has the same rank as the highest among them.
|
||||
Next, types with first-order universal quantification, such as `|T| T -> T`, or types that include them in the return value type are "rank 1".
|
||||
In addition, types with second-order universal quantification (types that have rank 1 types as arguments such as `(|T| T -> T) -> Int`) or types that include them in the return type are called "rank 2 ".
|
||||
The above is repeated to define the "Rank N" type. Also, the rank-N types include all types with a rank of N or less. Therefore, a type with mixed ranks has the same rank as the highest among them.
|
||||
|
||||
```python
|
||||
R1 = (|...| R0) or (R0 -> R1) or K(R1) or R0
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Kind
|
||||
|
||||
Everything is typed in Erg. Types themselves are no exception. __kind__ represents the “type of type”. For example, `Int` belongs to `Type`, just as `1` belongs to `Int`. `Type` is the simplest kind, the __atomic kind__. In type-theoretic notation, `Type` corresponds to `*`.
|
||||
Everything is typed in Erg. Types themselves are no exception. __kind__ represents the "type of type". For example, `Int` belongs to `Type`, just as `1` belongs to `Int`. `Type` is the simplest kind, the __atomic kind__. In type-theoretic notation, `Type` corresponds to `*`.
|
||||
|
||||
In the concept of kind, what is practically important is one or more kinds (multinomial kind). One-term kind, for example `Option`, belongs to it. A unary kind is represented as `Type -> Type` [<sup id="f1">1</sup>](#1). A __container__ such as `Array` or `Option` is specifically a polynomial kind that takes a type as an argument.
|
||||
As the notation `Type -> Type` indicates, `Option` is actually a function that receives a type `T` and returns a type `Option T`. However, since this function is not a function in the usual sense, it is usually called the unary kind.
|
||||
|
|
|
@ -22,7 +22,7 @@ Pythonからはオフサイドルールと互換言語として多くの意味
|
|||
A: Ergの設計動機の1つに、手軽に使えてなおかつ強力な型システムを持った言語がほしいというものがありました。すなわち、型推論、カインド、依存型などを持った言語です。
|
||||
Juliaは型付けができますが、実際のところは動的型付け言語であり、静的型付け言語のコンパイル時エラー検出というメリットを享受できません。
|
||||
|
||||
## Ergは関数型プログラミングやオブジェクト指向プログラミングなど複数のスタイルをサポートしています。これは、Pythonの”There should be one-- and preferably only one --obvious way to do it.”に反しているのではないですか?
|
||||
## Ergは関数型プログラミングやオブジェクト指向プログラミングなど複数のスタイルをサポートしています。これは、Pythonの"There should be one-- and preferably only one --obvious way to do it."に反しているのではないですか?
|
||||
|
||||
A: Ergでは、その言葉はもう少し狭い意味で捉えられます。例えば、一般にErgのAPIにエイリアスはありません。Ergはこの意味では"only one way"です。
|
||||
関数型やOOPなどのもう少し大きな意味・枠組みでは、1つのやり方しかないというのは必ずしも利便性をもたらすとは限りません。
|
||||
|
|
|
@ -10,8 +10,9 @@ Erg 自身の仮想マシン (Dyne) で所有権 + [Perceus](https://www.microso
|
|||
|
||||
LLVM では、WASM バックエンドは所有権 + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf) メモリ管理モデルを使用します
|
||||
|
||||
バックエンドに関係なく、メモリ管理の違いにより、コードを変更する必要はありません
|
||||
|
||||
__知らせ__:Ergが所有権システムを導入した動機は、Rustのような「GCに頼らないメモリ管理」のためではないからです。
|
||||
そもそも、現在のところErgはPythonバイトコードに落とし込まれる言語のため、結局GCは使用されます。
|
||||
Ergが所有権システムを導入した狙いは「可変状態の局所化」です。Ergでは、可変オブジェクトに所有権の概念がついています。
|
||||
これは、共有可変状態がバグの温床になりやすく、さらに型安全性まで侵害すること(詳しくは[こちら](../syntax/type/advanced/shared.md#共有参照SharedReference)を参照)をみての判断です。
|
||||
|
||||
|
|
|
@ -47,21 +47,21 @@ assert mut_dict["Alice"] == 145
|
|||
キー・値の型は単一でなくてもよく、そのような辞書を __非等質な辞書(heterogenous dict)__ といいます。
|
||||
|
||||
```python
|
||||
d: {Str: Int, Int: Str} = {”a”: 1, 1: “a”}
|
||||
assert d[”a”] == 1
|
||||
assert d[1] == “a”
|
||||
d: {Str: Int, Int: Str} = {"a": 1, 1: "a"}
|
||||
assert d["a"] == 1
|
||||
assert d[1] == "a"
|
||||
```
|
||||
|
||||
しかし、違う型のキーに同じ型の値、または同じ型のキーに違う型の値をあてることはできません。
|
||||
このような場合は代わりにOr型(Union)を使います。
|
||||
|
||||
```python
|
||||
invalid1 = {1: “a”, “a”: “b”}
|
||||
invalid2 = {1: “a”, 2: 2}
|
||||
invalid1 = {1: "a", "a": "b"}
|
||||
invalid2 = {1: "a", 2: 2}
|
||||
|
||||
# Ergの型推論はOr型を推論しないので、型指定が必要
|
||||
valid1: {Int or Str: Str} = {1: “a”, “a”: “b”}
|
||||
valid2: {Int: Int or Str} = {1: “a”, 2: 2}
|
||||
valid1: {Int or Str: Str} = {1: "a", "a": "b"}
|
||||
valid2: {Int: Int or Str} = {1: "a", 2: 2}
|
||||
```
|
||||
|
||||
<p align='center'>
|
||||
|
|
|
@ -378,7 +378,7 @@ Section 8 -- Interpretation.
|
|||
Creative Commons is not a party to its public
|
||||
licenses. Notwithstanding, Creative Commons may elect to apply one of
|
||||
its public licenses to material it publishes and in those instances
|
||||
will be considered the “Licensor.” The text of the Creative Commons
|
||||
will be considered the "Licensor." The text of the Creative Commons
|
||||
public licenses is dedicated to the public domain under the CC0 Public
|
||||
Domain Dedication. Except for the limited purpose of indicating that
|
||||
material is shared under a Creative Commons public license or as
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
### log(x: Object, type: LogType = Info) -> None
|
||||
|
||||
在调试显示中记录“x”。 执行完成后汇总并显示日志
|
||||
支持表情符号的终端根据“类型”添加前缀
|
||||
在调试显示中记录"x"。 执行完成后汇总并显示日志
|
||||
支持表情符号的终端根据"类型"添加前缀
|
||||
|
||||
* type == Info: 💬
|
||||
* type == Ok: ✅
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/modules/unit.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
`unit` 模块是将数值计算中经常使用的单位定义为类型的模块。
|
||||
Erg 数值类型包括 `Nat`、`Int`、`Ratio` 等。但是,这些类型没有关于“数字的含义”的信息,因此可以执行诸如添加米和码之类的无意义计算。
|
||||
Erg 数值类型包括 `Nat`、`Int`、`Ratio` 等。但是,这些类型没有关于"数字的含义"的信息,因此可以执行诸如添加米和码之类的无意义计算。
|
||||
通过使用 `unit` 模块,您可以避免错误,例如将不同单位的数字传递给函数。
|
||||
这样的错误确实会发生,并且会导致诸如[由于错误的单位系统导致火星探测器丢失](http://www.sydrose.com/case100/287/)之类的严重错误。
|
||||
如果您希望代码在进行数值计算时更加健壮,您应该使用此模块。
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
## `unsafe!`
|
||||
|
||||
执行“不安全”过程。 就像 Rust 一样,`Unsafe` API 不能直接调用,而是作为高阶函数传递给这个过程。
|
||||
执行"不安全"过程。 就像 Rust 一样,`Unsafe` API 不能直接调用,而是作为高阶函数传递给这个过程。
|
||||
|
||||
```python
|
||||
unsound = import "unsound"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/special.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
特殊形式是不能在 Erg 类型系统中表达的运算符、子程序(等等)。它被`包围,但实际上无法捕获。
|
||||
此外,为方便起见,还出现了“Pattern”、“Body”和“Conv”等类型,但不存在此类类型。它的含义也取决于上下文。
|
||||
此外,为方便起见,还出现了"Pattern"、"Body"和"Conv"等类型,但不存在此类类型。它的含义也取决于上下文。
|
||||
|
||||
## `=`(pat: Pattern, body: Body) -> NoneType
|
||||
|
||||
|
@ -33,7 +33,7 @@ L = X: Int -> Class(...)
|
|||
print! L # <kind L>
|
||||
```
|
||||
|
||||
`=` 运算符的返回值为“未定义”。
|
||||
`=` 运算符的返回值为"未定义"。
|
||||
函数中的多个赋值和 `=` 会导致语法错误。
|
||||
|
||||
```python
|
||||
|
@ -103,7 +103,7 @@ match [1, 2, 3]:
|
|||
|
||||
## del(x: ...T) -> NoneType | T
|
||||
|
||||
删除变量“x”。但是,无法删除内置对象。
|
||||
删除变量"x"。但是,无法删除内置对象。
|
||||
|
||||
```python
|
||||
a = 1
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
## 对象系统
|
||||
|
||||
Trait 类相当于 Python 中的 ABC(抽象基类,接口)
|
||||
实例属于1、True、“aaa”等。
|
||||
实例属于1、True、"aaa"等。
|
||||
类是 Int、Bool、Str 等。
|
||||
|
||||
### 类型
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/classes/Option.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
表示“可能失败”的类型。
|
||||
表示"可能失败"的类型。
|
||||
|
||||
## 方法
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
Result T, E <: Error = Either T, E
|
||||
```
|
||||
|
||||
和 `Option` 一样,它代表“一个可能失败的值”,但它可以有失败的上下文。 用法与`Either`几乎相同。
|
||||
和 `Option` 一样,它代表"一个可能失败的值",但它可以有失败的上下文。 用法与`Either`几乎相同。
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[.md%26commit_hash%3D06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/traits/Div(R,O).md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
如果除以零没有错误,请使用“SafeDiv”
|
||||
如果除以零没有错误,请使用"SafeDiv"
|
||||
|
||||
```python
|
||||
Div R, O = Trait {
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/traits/Sample.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
具有“随机”选择实例的`sample`和`sample!`方法的特征。`sample`方法总是返回相同的实例,而`sample!`方法返回一个随机实例,该实例随调用而变化
|
||||
具有"随机"选择实例的`sample`和`sample!`方法的特征。`sample`方法总是返回相同的实例,而`sample!`方法返回一个随机实例,该实例随调用而变化
|
||||
|
||||
请注意,这是一个假设您想要一个适当的实例进行测试等的特征,并且它不一定是随机的。 如果您想要随机抽样,请使用“随机”模块。
|
||||
请注意,这是一个假设您想要一个适当的实例进行测试等的特征,并且它不一定是随机的。 如果您想要随机抽样,请使用"随机"模块。
|
||||
|
||||
所有主要的值类都实现了 `Sample`。它还在由“Sample”类组成的元组类型、记录类型、Or类型和筛选类型中实现
|
||||
所有主要的值类都实现了 `Sample`。它还在由"Sample"类组成的元组类型、记录类型、Or类型和筛选类型中实现
|
||||
|
||||
```python
|
||||
assert Int.sample() == 42
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/compiler/TODO_hint.md&commit_hash=d15cbbf7b33df0f78a575cff9679d84c36ea3ab1)
|
||||
|
||||
* `x 未定义`(x 已被`Del` 删除)=> `提示:在第 X 行删除`
|
||||
*补丁方法重复:“提示:指定补丁(如`T.foo(1)`)或使用`Del`删除任何`.foo`”
|
||||
*补丁方法重复:"提示:指定补丁(如`T.foo(1)`)或使用`Del`删除任何`.foo`"
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
## 3. 类型检查和推断,转换 `AST` -> `HIR` (compiler/lower.rs)
|
||||
|
||||
* `HIR` 有每个变量的类型信息。它是用于“高级中间表示”的。
|
||||
* `HIR` 有每个变量的类型信息。它是用于"高级中间表示"的。
|
||||
* `HIR` 只保存变量的类型,但这已经足够了。在极端情况下,这是因为 Erg 只有转换(或运算符)应用程序的参数对象。
|
||||
* `ASTLower` 可以用与`Parser` 和`Lexer` 相同的方式构造。
|
||||
* 如果没有错误发生,`ASTLowerer::lower` 将输出 `HIR` 和 `CompileWarnings` 的元组。
|
||||
|
|
|
@ -83,12 +83,12 @@ pub enum Type {
|
|||
如果内容直到最后都保持为 None ,它将是一个无法确定为具体类型的类型变量(当场)。例如,具有 `id x = x` 的 `x` 类型。
|
||||
我将这种状态下的类型变量称为 __Unbound 类型变量__(我不知道确切的术语)。另一方面,我们将分配了某种具体类型的变量称为 __Linked 类型变量__。
|
||||
|
||||
两者都是自由类型变量(该术语显然以“自由变量”命名)。这些是编译器用于推理的类型变量。它之所以有这样一个特殊的名字,是因为它不同于程序员指定类型的类型变量,例如 `id: 'T -> 'T` 中的 `'T`。
|
||||
两者都是自由类型变量(该术语显然以"自由变量"命名)。这些是编译器用于推理的类型变量。它之所以有这样一个特殊的名字,是因为它不同于程序员指定类型的类型变量,例如 `id: 'T -> 'T` 中的 `'T`。
|
||||
|
||||
未绑定类型变量表示为`?T`、`?U`。在类型论的上下文中,经常使用 α 和 β,但这一种是用来简化输入的。
|
||||
请注意,这是出于一般讨论目的而采用的表示法,实际上并未使用字符串标识符实现。
|
||||
|
||||
进入类型环境时,未绑定的类型变量 `Type::Var` 被替换为 `Type::MonoQuantVar`。这称为 __quantified 类型变量__。这类似于程序员指定的类型变量,例如“T”。内容只是一个字符串,并没有像自由类型变量那样链接到具体类型的工具。
|
||||
进入类型环境时,未绑定的类型变量 `Type::Var` 被替换为 `Type::MonoQuantVar`。这称为 __quantified 类型变量__。这类似于程序员指定的类型变量,例如"T"。内容只是一个字符串,并没有像自由类型变量那样链接到具体类型的工具。
|
||||
|
||||
用量化类型变量替换未绑定类型变量的操作称为__generalization__(或泛化)。如果将其保留为未绑定类型变量,则类型将通过一次调用固定(例如,调用 `id True` 后,`id 1` 的返回类型将是 `Bool`),所以它必须是概括的。
|
||||
以这种方式,在类型环境中注册了包含量化类型变量的通用定义。
|
||||
|
@ -114,7 +114,7 @@ inst 'T = ?T (?T ∉ Γ)
|
|||
此外,如果表达式是调用,则获取返回类型的操作表示为 `subst_call_ret`。 第一个参数是参数类型列表,第二个参数是要分配的类型。
|
||||
|
||||
类型替换规则 `{?T --> X}` 意味着将 `?T` 和 `X` 重写为相同类型。 此操作称为 __Unification__。 `X` 也可以是类型变量。
|
||||
[单独部分](./unification.md) 中描述了详细的统一算法。 我们将统一操作表示为“统一”。
|
||||
[单独部分](./unification.md) 中描述了详细的统一算法。 我们将统一操作表示为"统一"。
|
||||
|
||||
```python
|
||||
unify(?T, Int) == Ok(()) # ?T == (Int)
|
||||
|
@ -128,7 +128,7 @@ subst_call_ret([X, Y], (?T, ?U) -> ?U) == Y
|
|||
## 半统一(semi-unification)
|
||||
|
||||
统一的一种变体称为半统一(__Semi-unification__)。 这是更新类型变量约束以满足子类型关系的操作。
|
||||
在某些情况下,类型变量可能是统一的,也可能不是统一的,因此称为“半”统一。
|
||||
在某些情况下,类型变量可能是统一的,也可能不是统一的,因此称为"半"统一。
|
||||
|
||||
例如,在参数分配期间会发生半统一。
|
||||
因为实际参数的类型必须是形式参数类型的子类型。
|
||||
|
@ -145,7 +145,7 @@ f(a)
|
|||
|
||||
## 泛化
|
||||
|
||||
泛化不是一项简单的任务。 当涉及多个作用域时,类型变量的“级别管理”就变得很有必要了。
|
||||
泛化不是一项简单的任务。 当涉及多个作用域时,类型变量的"级别管理"就变得很有必要了。
|
||||
为了看到层级管理的必要性,我们首先确认没有层级管理的类型推断会导致问题。
|
||||
推断以下匿名函数的类型。
|
||||
|
||||
|
@ -164,7 +164,7 @@ x(: ?T) ->
|
|||
y
|
||||
```
|
||||
|
||||
首先要确定的是右值 x 的类型。 右值是一种“用途”,因此我们将其具体化。
|
||||
首先要确定的是右值 x 的类型。 右值是一种"用途",因此我们将其具体化。
|
||||
但是 x 的类型 `?T` 已经被实例化了,因为它是一个自由变量。 Yo`?T` 成为右值的类型。
|
||||
|
||||
```python
|
||||
|
@ -187,7 +187,7 @@ x(: ?T) ->
|
|||
y
|
||||
```
|
||||
|
||||
y 的类型现在是一个量化类型变量“T”。 在下一行中,立即使用 `y`。 具体的。
|
||||
y 的类型现在是一个量化类型变量"T"。 在下一行中,立即使用 `y`。 具体的。
|
||||
|
||||
```python
|
||||
x: ?T ->
|
||||
|
@ -205,7 +205,7 @@ x: ?T ->
|
|||
|
||||
并查看生成的整个表达式的类型。 `?T -> ?U`。
|
||||
但显然这个表达式应该是`?T -> ?T`,所以我们知道推理有问题。
|
||||
发生这种情况是因为我们没有“级别管理”类型变量。
|
||||
发生这种情况是因为我们没有"级别管理"类型变量。
|
||||
|
||||
所以我们用下面的符号来介绍类型变量的层次。 级别表示为自然数。
|
||||
|
||||
|
|
|
@ -31,5 +31,5 @@ a = [1, 2, 3].iter().map i -> i + 1
|
|||
r = {x = 1; y = 2}
|
||||
```
|
||||
|
||||
左侧和右侧值的精确定义是“如果它是可评估的,则为右侧值,否则为左侧值”。
|
||||
左侧和右侧值的精确定义是"如果它是可评估的,则为右侧值,否则为左侧值"。
|
||||
例如,考虑代码 ``i = 1; i``,其中第二个 `i` 是右侧值,因为它是可评估的,但第一个 `i` 是左侧值。
|
|
@ -39,12 +39,12 @@ provided_method_table = {
|
|||
}
|
||||
```
|
||||
|
||||
具有 `.times` 方法的类型是 `Nat`、`Foo`。从这些中,找到与“{1}”类型匹配的一个。
|
||||
具有 `.times` 方法的类型是 `Nat`、`Foo`。从这些中,找到与"{1}"类型匹配的一个。
|
||||
有两种类型的符合性确定。它们是筛式判断和记录式判断。这是通过筛子类型确定来完成的。
|
||||
|
||||
##筛型确定
|
||||
|
||||
检查候选类型是否与 `1` 的类型 `{1}` 兼容。与“{1}”兼容的筛子类型有“{0, 1}”、“0..9”等。
|
||||
检查候选类型是否与 `1` 的类型 `{1}` 兼容。与"{1}"兼容的筛子类型有"{0, 1}"、"0..9"等。
|
||||
有限元代数类型,例如 `0..1 或 3..4`、`-1..2 和 0..3`,在声明为基本类型(即 {0, 1, 3, 4}`,`{0, 1, 2}`)。
|
||||
在这种情况下,`Nat` 是 `0.._ == {I: Int | I >= 0}`,所以 `{1}` 与 `Nat` 兼容。
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
~~A:Erg的可执行系统EVM(Erg VirtualMachine)执行Erg字节码,是Python字节码的扩展。它在 Python 字节码中引入了静态类型系统和其他特性(例如向不带参数的指令引入参数,以及在自由编号中实现唯一指令)。这让 Erg 可以无缝调用 Python 代码并快速执行。~~
|
||||
|
||||
A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Python 相同的解释器上。最初,我们计划开发一个兼容 Cpython 的解释器,并将其与编译器结合起来形成“Erg”。但是,由于处理系统的发展远远落后于编译器,我们决定提前只发布编译器(但解释器仍在开发中)。
|
||||
A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Python 相同的解释器上。最初,我们计划开发一个兼容 Cpython 的解释器,并将其与编译器结合起来形成"Erg"。但是,由于处理系统的发展远远落后于编译器,我们决定提前只发布编译器(但解释器仍在开发中)。
|
||||
|
||||
## 哪些语言影响了Erg?
|
||||
|
||||
|
@ -22,15 +22,15 @@ A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Pyth
|
|||
答:Erg 设计的动机之一是拥有一种易于使用且具有强大类型系统的语言。即具有类型推断、Kind、依赖类型等的语言。
|
||||
Julia 是可以有类型的,但它确实是一种动态类型语言,不具备静态类型语言的编译时错误检测优势。
|
||||
|
||||
## Erg 支持多种编程风格,包括函数式和面向对象的编程。这不是与 Python 的“应该有一种——最好只有一种——明显的方法”相反吗?
|
||||
## Erg 支持多种编程风格,包括函数式和面向对象的编程。这不是与 Python 的"应该有一种——最好只有一种——明显的方法"相反吗?
|
||||
|
||||
答:在 Erg 中,该术语是在更狭窄的上下文中使用的。例如,Erg API 中一般没有别名;在这种情况下,Erg是“唯一一种方式”。
|
||||
答:在 Erg 中,该术语是在更狭窄的上下文中使用的。例如,Erg API 中一般没有别名;在这种情况下,Erg是"唯一一种方式"。
|
||||
在更大的上下文中,例如 FP 或 OOP,只有一种做事方式并不一定很方便。
|
||||
例如,JavaScript 有几个库可以帮助创建不可变的程序,而 C 有几个用于垃圾收集的库。
|
||||
然而,即使是这样的基本功能也有多个库不仅需要时间来选择,而且在集成使用不同库的代码时也会产生很大的困难。
|
||||
即使在纯函数式语言 Haskell 中,也有支持 OOP 的库。
|
||||
如果程序员没有一些东西,他们会自己创造它们。因此,我们认为将它们作为标准提供会更好。
|
||||
这也符合 Python 的“含电池”概念。
|
||||
这也符合 Python 的"含电池"概念。
|
||||
|
||||
## Erg 这个名字的由来是什么?
|
||||
|
||||
|
|
|
@ -4,15 +4,16 @@
|
|||
|
||||
## Erg内存管理模型
|
||||
|
||||
在CPython后端中使用所有权 + Python内存管理模型(不过Erg代码中的循环引用不会通过GC处理[详见](syntax/18_ownership.md/#循环引用))
|
||||
在CPython后端中使用所有权 + Python内存管理模型(不过Erg代码中的循环引用不会通过GC处理详见[此处](syntax/18_ownership.md/#循环引用))
|
||||
|
||||
在Erg自己的虚拟机(Dyne)中使用所有权 + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf)内存管理模型,如果Erg代码使用了Python API那么这些Erg代码使用跟踪垃圾回收内存管理模型
|
||||
|
||||
在LLVM, WASM后端使用所有权 + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf)内存管理模型
|
||||
|
||||
__注意__: Erg 引入所有权系统的动机不是像 Rust 那样“不依赖 GC 的内存管理”。
|
||||
首先,Erg 目前唯一可用前端编译Erg为Python字节码,因此使用了 GC。
|
||||
Erg 所有权系统的目标是“可变状态的本地化”。 Erg 有一个附属于可变对象的所有权概念。
|
||||
无论是什么后端都不需要因为内存管理的不同对代码进行任何更改
|
||||
|
||||
__注意__: Erg 引入所有权系统的动机不是像 Rust 那样"不依赖 GC 的内存管理"。
|
||||
Erg 所有权系统的目标是"可变状态的本地化"。 Erg 有一个附属于可变对象的所有权概念。
|
||||
这是因为共享可变状态容易出现错误,甚至违反类型安全(参见 [此处](../syntax/type/advanced/shared.md#共享参考))。这是一个判断决定。
|
||||
|
||||
## 为什么类型参数要大括号 || 而不是 <> 或 []?
|
||||
|
@ -75,7 +76,7 @@ try!:
|
|||
exit 1
|
||||
```
|
||||
|
||||
在引入 Python 函数时,缺省情况下,所有函数都被视为包含异常,返回类型为。如果你知道不调度异常,请在<gtr=“12”/>中指明。
|
||||
在引入 Python 函数时,缺省情况下,所有函数都被视为包含异常,返回类型为。如果你知道不调度异常,请在<gtr="12"/>中指明。
|
||||
|
||||
此外,Erg 没有引入异常机制的另一个原因是它计划引入并行编程的功能。这是因为异常机制与并行执行不兼容(例如,如果并行执行导致多个异常,则很难处理)。
|
||||
|
||||
|
@ -111,6 +112,6 @@ A:没有那个计划。最重要的原因是,如果允许定义自己的运
|
|||
|
||||
但是,确实也不是没有方法可以不在语言上特殊对待副作用。例如,可以用代数效果(类型系统上的功能)替代过程。但这样的合一并不总是正确的。例如,Haskell 没有对字符串进行特殊处理,只是一个字符数组,但这种抽象是错误的。
|
||||
|
||||
什么情况下,可以说合一化是错的?一个指标是“是否会因其合一而难以看到错误信息”。Erg 设计师发现,将副作用特殊处理会使错误消息更容易阅读。
|
||||
什么情况下,可以说合一化是错的?一个指标是"是否会因其合一而难以看到错误信息"。Erg 设计师发现,将副作用特殊处理会使错误消息更容易阅读。
|
||||
|
||||
Erg 有一个强大的类型系统,但并不是所有的类型都决定了它。如果这样做了,你的下场就跟 Java 试图用类来控制一切一样。
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
答:不,没有。所有对象都至少属于 `Object` 类,但是这种类型只提供了一组最小的属性,所以你不能像使用 Any 那样对它做任何你想做的事情。
|
||||
`Object` 类通过`match` 等动态检查转换为所需的类型。它与Java 和其他语言中的`Object` 是同一种。
|
||||
在 Erg 世界中,没有像 TypeScript 那样的混乱和绝望,其中 API 定义是“Any”。
|
||||
在 Erg 世界中,没有像 TypeScript 那样的混乱和绝望,其中 API 定义是"Any"。
|
||||
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么区别?
|
||||
|
||||
A:`Never` 是一种“不可能”的类型。产生运行时错误的子例程将“Never”(或“Never”的合并类型)作为其返回类型。该程序将在检测到这一点后立即停止。尽管 `Never` 类型在定义上也是所有类型的子类,但 `Never` 类型的对象永远不会出现在 Erg 代码中,也永远不会被创建。 `{}` 等价于 `Never`。
|
||||
A:`Never` 是一种"不可能"的类型。产生运行时错误的子例程将"Never"(或"Never"的合并类型)作为其返回类型。该程序将在检测到这一点后立即停止。尽管 `Never` 类型在定义上也是所有类型的子类,但 `Never` 类型的对象永远不会出现在 Erg 代码中,也永远不会被创建。 `{}` 等价于 `Never`。
|
||||
`Ellipsis` 是一个表示省略号的对象,来自 Python。
|
||||
`NotImplemented` 也来自 Python。它被用作未实现的标记,但 Erg 更喜欢产生错误的 `todo` 函数。
|
||||
`None` 是 `NoneType` 的一个实例。它通常与 `Option` 类型一起使用。
|
||||
`()` 是一个单元类型和它自己的一个实例。当您想要返回“无意义的值”(例如过程的返回值)时使用它。
|
||||
`()` 是一个单元类型和它自己的一个实例。当您想要返回"无意义的值"(例如过程的返回值)时使用它。
|
||||
|
||||
## 为什么 `x = p!()` 有效但 `f() = p!()` 会导致 EffectError?
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ stack.push(consts[namei])
|
|||
```
|
||||
|
||||
在常量表中加载常量。
|
||||
目前(Python 3.9),在 CPython 中,每个 lambda 函数都是 MAKE_FUNCTION,名称为“\<lambda\>”
|
||||
目前(Python 3.9),在 CPython 中,每个 lambda 函数都是 MAKE_FUNCTION,名称为"\<lambda\>"
|
||||
|
||||
```console
|
||||
>>> dis.dis("[1,2,3].map(lambda x: x+1)")
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
## PyString 对象
|
||||
|
||||
* 如果我使用 ascii 以外的字符,它会变成 PyUnicode 吗?
|
||||
* “あ”、“𠮷”和“α”是 PyUnicode(不再使用?)
|
||||
* "あ"、"𠮷"和"α"是 PyUnicode(不再使用?)
|
||||
|
||||
* 0 字节:0x73(表示`s`)
|
||||
* 1~4 字节:字符串长度
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module
|
||||
File "<stdin>", line 3, in g
|
||||
类型错误:只能将str(不是“int”)连接到str
|
||||
类型错误:只能将str(不是"int")连接到str
|
||||
```
|
||||
|
||||
Erg 静态检查与父类的一致性。
|
||||
重写时必须给出“Override”装饰器,并且重写函数的类型必须是被重写函数类型的子类型。
|
||||
重写时必须给出"Override"装饰器,并且重写函数的类型必须是被重写函数类型的子类型。
|
||||
|
||||
```python
|
||||
>>> C = Class()
|
||||
|
@ -61,7 +61,7 @@ Erg 静态检查与父类的一致性。
|
|||
>>> D = Inherit C
|
||||
... .f self = "a"
|
||||
...
|
||||
错误[#XX]:文件“<stdin>”,第 5 行,在 D 中
|
||||
错误[#XX]:文件"<stdin>",第 5 行,在 D 中
|
||||
要覆盖 f,必须添加 `Override` 装饰器,其类型必须是 `Self.() -> Nat` 或其子类型
|
||||
f(self) 已在 C 中定义。要覆盖 f,必须添加 `Override` 装饰器,其类型必须为 `Self. 要覆盖,必须给它一个 `Override` 装饰器,并且它的类型必须是 `Self.() -> Nat` 或 that.f(self) 的子类型。
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
## 你好,世界!
|
||||
|
||||
首先,让我们做“Hello World”。
|
||||
首先,让我们做"Hello World"。
|
||||
|
||||
```python
|
||||
print!("Hello, World!")
|
||||
|
@ -30,8 +30,8 @@ print!(f(x, y)) # OK
|
|||
print! f(x, y) # OK
|
||||
print! f(x, g y) # OK
|
||||
print! f x, y # NG, 可以理解为 `print!(f(x), y)` 或 `print!(f(x, y))` print!
|
||||
print!(f x, y) # NG, 可以表示“print!(f(x),y)”或“print!(f(x,y))”
|
||||
print! f(x, g y, z) # NG, 可以表示“print!(x,g(y),z)”或“print!(x,g(y,z))”
|
||||
print!(f x, y) # NG, 可以表示"print!(f(x),y)"或"print!(f(x,y))"
|
||||
print! f(x, g y, z) # NG, 可以表示"print!(x,g(y),z)"或"print!(x,g(y,z))"
|
||||
```
|
||||
|
||||
## 脚本
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
0.00, -0.0, 0.1, 400.104, ...
|
||||
```
|
||||
|
||||
如果“比率”文字的整数或小数部分为`0`,则可以省略`0`
|
||||
如果"比率"文字的整数或小数部分为`0`,则可以省略`0`
|
||||
|
||||
```python
|
||||
assert 1.0 == 1.
|
||||
|
@ -46,7 +46,7 @@ assert "\{1+1}\" == "\{{s}\}"
|
|||
|
||||
### 指数字面量
|
||||
|
||||
这是学术计算中常用的表示指数符号的文字。 它是“比率”类型的一个实例。
|
||||
这是学术计算中常用的表示指数符号的文字。 它是"比率"类型的一个实例。
|
||||
该符号与 Python 中的符号相同。
|
||||
|
||||
```python
|
||||
|
@ -135,7 +135,7 @@ assert 0.0f32 == 0.0f64
|
|||
1+2im, 0.4-1.2im, 0im, im
|
||||
```
|
||||
|
||||
一个“复杂”对象只是一个虚数单位对象`im`的算术组合
|
||||
一个"复杂"对象只是一个虚数单位对象`im`的算术组合
|
||||
|
||||
## *-less 乘法
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
n = 1
|
||||
```
|
||||
|
||||
以这种方式定义的“n”此后可以用作表示整数对象“1”的变量。 该系统称为分配(或绑定)。
|
||||
以这种方式定义的"n"此后可以用作表示整数对象"1"的变量。 该系统称为分配(或绑定)。
|
||||
我们刚刚说过`1`是一个对象。 稍后我们将讨论对象是什么,但现在我们假设它是可以赋值的,即在赋值运算符的右侧(`=` 等)。
|
||||
|
||||
如果要指定变量的“类型”,请执行以下操作。 类型大致是一个对象所属的集合,后面会解释。
|
||||
如果要指定变量的"类型",请执行以下操作。 类型大致是一个对象所属的集合,后面会解释。
|
||||
这里我们指定`n`是自然数(`Nat`)类型。
|
||||
|
||||
```python
|
||||
|
@ -39,7 +39,7 @@ i = i + 1 # 分配错误:不能分配两次
|
|||
```
|
||||
|
||||
您可以在内部范围内定义具有相同名称的变量,但您只是覆盖它,而不是破坏性地重写它的值。 如果您返回外部范围,该值也会返回。
|
||||
请注意,这是与 Python “语句”范围不同的行为。
|
||||
请注意,这是与 Python "语句"范围不同的行为。
|
||||
这种功能通常称为阴影。 但是,与其他语言中的阴影不同,您不能在同一范围内进行阴影。
|
||||
|
||||
```python
|
||||
|
@ -119,7 +119,7 @@ Del y, Z
|
|||
f(2) # 名称错误:f 未定义(在第 6 行中删除)
|
||||
```
|
||||
|
||||
注意 `Del` 只能删除用户自定义模块中定义的变量。 无法删除诸如“True”之类的内置常量。
|
||||
注意 `Del` 只能删除用户自定义模块中定义的变量。 无法删除诸如"True"之类的内置常量。
|
||||
|
||||
```python
|
||||
Del True # 类型错误:无法删除内置常量
|
||||
|
@ -149,7 +149,7 @@ C == D # 类型错误:无法比较类对象
|
|||
```
|
||||
|
||||
严格来说,`=` 不会将右侧的值直接分配给左侧的标识符。
|
||||
在函数和类对象的情况下,执行“修改”,例如将变量名称信息赋予对象。 但是,结构类型并非如此。
|
||||
在函数和类对象的情况下,执行"修改",例如将变量名称信息赋予对象。 但是,结构类型并非如此。
|
||||
|
||||
```python
|
||||
f x = x
|
||||
|
|
|
@ -17,7 +17,7 @@ i: {2}
|
|||
```
|
||||
|
||||
赋值后的声明类似于`assert`的类型检查,但具有在编译时检查的特点。
|
||||
在运行时通过`assert`进行类型检查可以检查“可能是Foo类型”,但是在编译时通过`:`进行类型检查是严格的:如果类型未确定为“类型Foo”,则不会通过 检查会出现错误。
|
||||
在运行时通过`assert`进行类型检查可以检查"可能是Foo类型",但是在编译时通过`:`进行类型检查是严格的:如果类型未确定为"类型Foo",则不会通过 检查会出现错误。
|
||||
|
||||
```python
|
||||
i = (-1..10).sample!
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/04_function.md&commit_hash=51de3c9d5a9074241f55c043b9951b384836b258)
|
||||
|
||||
函数是一个块,它接受一个“参数”,对其进行处理,并将其作为“返回值”返回。 定义如下。
|
||||
函数是一个块,它接受一个"参数",对其进行处理,并将其作为"返回值"返回。 定义如下。
|
||||
|
||||
```python
|
||||
add x, y = x + y
|
||||
|
@ -126,7 +126,7 @@ f x := 1, y := x = ... # NG
|
|||
输出其参数的日志(记录)的 `log` 函数可以采用任意数量的参数。
|
||||
|
||||
```python
|
||||
记录“你好”、“世界”、“!” # 你好世界 !
|
||||
记录"你好"、"世界"、"!" # 你好世界 !
|
||||
```
|
||||
|
||||
要定义这样的函数,请将 `...` 添加到参数中。 这样,函数将参数作为可变长度数组接收
|
||||
|
@ -158,7 +158,7 @@ fib 1 = 1
|
|||
fib(n: Nat): Nat = fib(n - 1) + fib(n - 2)
|
||||
```
|
||||
|
||||
注意一个函数定义有多个模式不是所谓的重载(multiple definition); 一个函数只有一个定义。 在上面的示例中,“n”必须与“0”或“1”属于同一类型。 此外,与 `match` 一样,模式匹配是从上到下完成的。
|
||||
注意一个函数定义有多个模式不是所谓的重载(multiple definition); 一个函数只有一个定义。 在上面的示例中,"n"必须与"0"或"1"属于同一类型。 此外,与 `match` 一样,模式匹配是从上到下完成的。
|
||||
|
||||
如果不同类的实例混合在一起,最后一个定义必须指定函数参数的类型为`Or`
|
||||
|
||||
|
@ -190,7 +190,7 @@ fib 1 = 1
|
|||
|
||||
递归函数是在其定义中包含自身的函数。
|
||||
|
||||
作为一个简单的例子,让我们定义一个执行阶乘计算的函数`factorial`。 阶乘是“将所有小于或等于的正数相乘”的计算。
|
||||
作为一个简单的例子,让我们定义一个执行阶乘计算的函数`factorial`。 阶乘是"将所有小于或等于的正数相乘"的计算。
|
||||
5 的阶乘是 `5*4*3*2*1 == 120`。
|
||||
|
||||
```python
|
||||
|
@ -214,7 +214,7 @@ factorial 1 = 1
|
|||
factorial n = n * factorial(n - 1)
|
||||
```
|
||||
|
||||
但是,即使您可以推理,您也应该明确指定递归函数的类型。 在上面的例子中,像“factorial(-1)”这样的代码可以工作,但是
|
||||
但是,即使您可以推理,您也应该明确指定递归函数的类型。 在上面的例子中,像"factorial(-1)"这样的代码可以工作,但是
|
||||
|
||||
```python
|
||||
factorial(-1) == -1 * factorial(-2) == -1 * -2 * factorial(-3) == ...
|
||||
|
|
|
@ -13,7 +13,7 @@ result: Option Int = if! Bool.sample!(), do:
|
|||
print! result # None (or 1)
|
||||
```
|
||||
|
||||
`.sample!()` 返回一组随机值。 如果返回值为真,`print! “真”`被执行。
|
||||
`.sample!()` 返回一组随机值。 如果返回值为真,`print! "真"`被执行。
|
||||
如果条件为假,您还可以指定要执行的操作; 第二个 do 块称为 else 块。
|
||||
|
||||
```python
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/07_side_effect.md&commit_hash=51de3c9d5a9074241f55c043b9951b384836b258)
|
||||
|
||||
我们一直忽略了解释“!”的含义,但现在它的含义终于要揭晓了。 这个 `!` 表示这个对象是一个带有“副作用”的“过程”。 过程是具有副作用的函数。
|
||||
我们一直忽略了解释"!"的含义,但现在它的含义终于要揭晓了。 这个 `!` 表示这个对象是一个带有"副作用"的"过程"。 过程是具有副作用的函数。
|
||||
|
||||
```python
|
||||
f x = print! x # EffectError: 不能为函数分配有副作用的对象
|
||||
|
@ -82,11 +82,11 @@ D = Class {i = Int}
|
|||
assert C == D # 类型错误:无法比较类
|
||||
```
|
||||
|
||||
言归正传:Erg 中“副作用”的准确定义是
|
||||
言归正传:Erg 中"副作用"的准确定义是
|
||||
|
||||
* 访问可变的外部信息。
|
||||
|
||||
“外部”一般是指外部范围; Erg 无法触及的计算机资源和执行前/执行后的信息不包含在“外部”中。 “访问”包括阅读和写作。
|
||||
"外部"一般是指外部范围; Erg 无法触及的计算机资源和执行前/执行后的信息不包含在"外部"中。 "访问"包括阅读和写作。
|
||||
|
||||
例如,考虑 `print!` 过程。 乍一看,`print!` 似乎没有重写任何变量。 但如果它是一个函数,它可以重写外部变量,例如,使用如下代码:
|
||||
|
||||
|
@ -103,7 +103,7 @@ image = cam.shot!()
|
|||
n = ocr.read_num(image) # n = 3.141592
|
||||
```
|
||||
|
||||
将“camera”模块视为为特定相机产品提供 API 的外部库,将“ocr”视为用于 OCR(光学字符识别)的库。
|
||||
将"camera"模块视为为特定相机产品提供 API 的外部库,将"ocr"视为用于 OCR(光学字符识别)的库。
|
||||
直接的副作用是由 `cam.shot!()` 引起的,但显然这些信息是从 `f` 泄露的。 因此,`print!` 本质上不可能是一个函数。
|
||||
|
||||
然而,在某些情况下,您可能希望临时检查函数中的值,而不想为此目的在相关函数中添加 `!`。 在这种情况下,可以使用 `log` 函数。
|
||||
|
@ -116,7 +116,7 @@ print! "this will be printed immediately"
|
|||
# 这将在执行后打印
|
||||
```
|
||||
|
||||
如果没有反馈给程序,或者换句话说,如果没有外部对象可以使用内部信息,那么信息的“泄漏”是可以允许的。 只需要不“传播”信息。
|
||||
如果没有反馈给程序,或者换句话说,如果没有外部对象可以使用内部信息,那么信息的"泄漏"是可以允许的。 只需要不"传播"信息。
|
||||
|
||||
<p align='center'>
|
||||
<a href='./06_operator.md'>上一页</a> | <a href='./08_procedure.md'>下一页</a>
|
||||
|
|
|
@ -68,7 +68,7 @@ Unit 是所有元素 0 元组的父类。
|
|||
() > (Str; 0)
|
||||
```
|
||||
|
||||
该对象的用途是用于没有参数和没有返回值的过程等。Erg 子例程必须有参数和返回值。 但是,在某些情况下,例如过程,可能没有有意义的参数或返回值,只有副作用。 在这种情况下,我们将单位用作“无意义的正式值”
|
||||
该对象的用途是用于没有参数和没有返回值的过程等。Erg 子例程必须有参数和返回值。 但是,在某些情况下,例如过程,可能没有有意义的参数或返回值,只有副作用。 在这种情况下,我们将单位用作"无意义的正式值"
|
||||
|
||||
```python
|
||||
# ↓ Actually, this parenthesis is a unit
|
||||
|
@ -78,12 +78,12 @@ p!() =.
|
|||
p!: () => ()
|
||||
```
|
||||
|
||||
但是,在这种情况下,Python 倾向于使用“无”而不是单位。
|
||||
但是,在这种情况下,Python 倾向于使用"无"而不是单位。
|
||||
在 Erg 中,当您从一开始就确定操作不会返回有意义的值(例如在过程中)时,您应该使用 `()`,并且当操作可能失败并且您可能会返回 `None` 将一无所获,例如在检索元素时。
|
||||
|
||||
## 参数和元组
|
||||
|
||||
实际上,Erg 的所有 `Callable` 对象都是一个参数和一个返回值; 一个接受 N 个参数的子例程只是接收“一个具有 N 个元素的元组”作为参数。
|
||||
实际上,Erg 的所有 `Callable` 对象都是一个参数和一个返回值; 一个接受 N 个参数的子例程只是接收"一个具有 N 个元素的元组"作为参数。
|
||||
|
||||
```python
|
||||
# f x = ... 被隐式假设为 f(x) = ... 被认为是
|
||||
|
@ -101,7 +101,7 @@ assert f in T: {(T,) -> T | T}
|
|||
assert g in {(Int, ... (Int; N)) -> (Int; N) | N: Nat}
|
||||
```
|
||||
|
||||
准确地说,函数的输入不是元组,而是“具有默认属性的命名元组”。 这是一个特殊的元组,只能在函数参数中使用,可以像记录一样命名,并且可以有默认值。
|
||||
准确地说,函数的输入不是元组,而是"具有默认属性的命名元组"。 这是一个特殊的元组,只能在函数参数中使用,可以像记录一样命名,并且可以有默认值。
|
||||
|
||||
```python
|
||||
f(x: Int, y=0) = x + y
|
||||
|
|
|
@ -9,7 +9,7 @@ ids = {"Alice": 145, "Bob": 214, "Charlie": 301}
|
|||
assert ids["Alice"] == 145
|
||||
```
|
||||
|
||||
如果键是“哈希”对象,则键不必是字符串。
|
||||
如果键是"哈希"对象,则键不必是字符串。
|
||||
|
||||
```python
|
||||
# 不推荐使用范围对象作为键(与切片混淆)
|
||||
|
|
|
@ -67,7 +67,7 @@ john: Named
|
|||
|
||||
greet! n: Named =
|
||||
print! "Hello, I am {n.name}"
|
||||
john # “你好,我是约翰 print!
|
||||
john # "你好,我是约翰 print!
|
||||
|
||||
Named.name # Str
|
||||
```
|
||||
|
|
|
@ -18,7 +18,7 @@ for! 0..9, i =>
|
|||
for!: |T: Type, I <: Iterable T| (I, T => None) => None
|
||||
```
|
||||
|
||||
第一个参数似乎接受“Iterable”类型的对象。
|
||||
第一个参数似乎接受"Iterable"类型的对象。
|
||||
|
||||
`Iterable` 是一个具有`.Iterator` 属性的类型,`.iter` 方法在request 方法中。
|
||||
|
||||
|
@ -43,7 +43,7 @@ log (1..3).iter() # <Range迭代器对象>
|
|||
|
||||
`ArrayIterator` 和 `RangeIterator` 都是实现 `Iterator` 的类,它们的存在只是为了提供 `Array` 和 `Range` 迭代函数。
|
||||
这种设计模式称为伴生类 [<sup id="f1">1</sup>](#1)。
|
||||
而“IteratorImpl”补丁是迭代功能的核心。 `Iterator` 只需要一个`.next` 方法,`IteratorImpl` 确实提供了几十种方法。 `ArrayIterator`和`RangeIterator`只需实现`.next`方法就可以使用`IteratorImpl`的实现方法。 为了方便起见,标准库实现了许多迭代器。
|
||||
而"IteratorImpl"补丁是迭代功能的核心。 `Iterator` 只需要一个`.next` 方法,`IteratorImpl` 确实提供了几十种方法。 `ArrayIterator`和`RangeIterator`只需实现`.next`方法就可以使用`IteratorImpl`的实现方法。 为了方便起见,标准库实现了许多迭代器。
|
||||
|
||||
```mermaid
|
||||
classDiagram
|
||||
|
|
|
@ -33,7 +33,7 @@ print! id! _a # 0x000002A798DFE980
|
|||
|
||||
`id!` 过程返回对象驻留的内存地址。
|
||||
|
||||
`b` 是一个 `Nat` “动态” 数组。 对象的内容发生了变化,但变量指向的是同一个东西
|
||||
`b` 是一个 `Nat` "动态" 数组。 对象的内容发生了变化,但变量指向的是同一个东西
|
||||
|
||||
```python
|
||||
b = ![1, 2, 3]
|
||||
|
@ -51,7 +51,7 @@ print! i # 1
|
|||
```
|
||||
|
||||
`!` 是一个特殊的运算符,称为 __mutation 运算符__。 它使不可变对象可变。
|
||||
标有“!”的对象的行为可以自定义。
|
||||
标有"!"的对象的行为可以自定义。
|
||||
|
||||
```python
|
||||
Point = Class {.x = Int; .y = Int}
|
||||
|
@ -98,7 +98,7 @@ match! x:
|
|||
|
||||
变量和标识符之间的区别在于,如果我们在 Erg 的语法理论意义上谈论变量,则两者实际上是相同的。
|
||||
在 C 中,类型和函数不能分配给变量; int 和 main 是标识符,而不是变量(严格来说可以赋值,但有限制)。
|
||||
然而,在Erg语中,“一切都是对象”。不仅函数和类型,甚至运算符都可以分配给变量。
|
||||
然而,在Erg语中,"一切都是对象"。不仅函数和类型,甚至运算符都可以分配给变量。
|
||||
|
||||
<p align='center'>
|
||||
<a href='./16_iterator.md'>上一页</a> | <a href='./18_ownership.md'>下一页</a>
|
||||
|
|
|
@ -34,7 +34,7 @@ print!w # [1, 2, 3, 4]
|
|||
复制的对象与原始对象完全相同,但相互独立,不受更改影响。
|
||||
|
||||
复制相当于 Python 的深拷贝,由于它完全重新创建相同的对象,因此计算和内存成本通常高于冻结和借用。
|
||||
需要复制对象的子例程被称为“参数消耗”子例程。
|
||||
需要复制对象的子例程被称为"参数消耗"子例程。
|
||||
|
||||
```python
|
||||
capitalize s: Str!=
|
||||
|
@ -80,7 +80,7 @@ peek_str s
|
|||
```
|
||||
|
||||
借来的值称为原始对象的 __reference__。
|
||||
您可以“转租”对另一个子例程的引用,但您不能使用它,因为您只是借用它。
|
||||
您可以"转租"对另一个子例程的引用,但您不能使用它,因为您只是借用它。
|
||||
|
||||
```python
|
||||
steal_str ref(s: Str!) =
|
||||
|
|
|
@ -120,7 +120,7 @@ Foo.
|
|||
{Foo; ...} = import "foo"
|
||||
|
||||
foo = Foo.new()
|
||||
foo.public() # 属性错误:“Foo”没有属性“public”(“public”在模块“bar”中定义)
|
||||
foo.public() # 属性错误:"Foo"没有属性"public"("public"在模块"bar"中定义)
|
||||
```
|
||||
|
||||
此外,方法不能在要重新导出的类型中定义。
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/23_closure.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
Erg 子例程有一个称为“闭包”的功能,可以捕获外部变量。
|
||||
Erg 子例程有一个称为"闭包"的功能,可以捕获外部变量。
|
||||
|
||||
```python
|
||||
outer = 1
|
||||
|
|
|
@ -39,12 +39,12 @@ assert record.method() == 3
|
|||
|
||||
## 元素
|
||||
|
||||
属于特定类型的对象(例如,“1”是“Int”类型的元素)。所有对象至少是`{=}`类型的元素。
|
||||
属于特定类型的对象(例如,"1"是"Int"类型的元素)。所有对象至少是`{=}`类型的元素。
|
||||
类的元素有时称为实例。
|
||||
|
||||
## 子程序
|
||||
|
||||
表示作为函数或过程(包括方法)实例的对象。代表子程序的类是“子程序”。
|
||||
表示作为函数或过程(包括方法)实例的对象。代表子程序的类是"子程序"。
|
||||
实现 `.__call__` 的对象通常称为 `Callable`。
|
||||
|
||||
## 可调用
|
||||
|
@ -68,11 +68,11 @@ Erg 函数的定义与 Python 的不同,因为它们不允许副作用。
|
|||
|
||||
## 程序
|
||||
|
||||
它对外部变量具有读取和“自我”权限,对静态变量具有读/写权限,并允许使用所有子例程。它可能有外部副作用。
|
||||
它对外部变量具有读取和"自我"权限,对静态变量具有读/写权限,并允许使用所有子例程。它可能有外部副作用。
|
||||
|
||||
## 方法
|
||||
|
||||
隐式将“self”作为第一个参数的子例程。它与简单的函数/过程是不同的类型。
|
||||
隐式将"self"作为第一个参数的子例程。它与简单的函数/过程是不同的类型。
|
||||
|
||||
## 实体
|
||||
|
||||
|
|
|
@ -97,7 +97,7 @@ i = g(1)?
|
|||
## 恐慌
|
||||
|
||||
Erg 还有一种处理不可恢复错误的机制,称为 __panicing__。
|
||||
不可恢复的错误是由外部因素引起的错误,例如软件/硬件故障、严重到无法继续执行代码的错误或程序员未预料到的错误。 等如果发生这种情况,程序将立即终止,因为程序员的努力无法恢复正常运行。 这被称为“恐慌”。
|
||||
不可恢复的错误是由外部因素引起的错误,例如软件/硬件故障、严重到无法继续执行代码的错误或程序员未预料到的错误。 等如果发生这种情况,程序将立即终止,因为程序员的努力无法恢复正常运行。 这被称为"恐慌"。
|
||||
|
||||
恐慌是通过 `panic` 功能完成的。
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ print(foo.private) # 属性错误:
|
|||
|
||||
## 从 Python 导入
|
||||
|
||||
默认情况下,从 Python 导入的所有对象都是“Object”类型。 由于此时无法进行比较,因此有必要细化类型。
|
||||
默认情况下,从 Python 导入的所有对象都是"Object"类型。 由于此时无法进行比较,因此有必要细化类型。
|
||||
|
||||
## 标准库中的类型规范
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@ lib 包的入口点是`src/lib.er`。导入包相当于导入 `lib.er`。
|
|||
|
||||
一个包有一个称为模块的子结构,在 Erg 中是一个 Erg 文件或由 Erg 文件组成的目录。外部 Erg 文件/目录是作为模块对象的可操作对象。
|
||||
|
||||
为了将目录识别为模块,有必要在目录中放置一个“(目录名称).er”文件。
|
||||
为了将目录识别为模块,有必要在目录中放置一个"(目录名称).er"文件。
|
||||
这类似于 Python 的 `__init__.py`,但与 `__init__.py` 不同的是,它放在目录之外。
|
||||
|
||||
例如,考虑以下目录结构。
|
||||
|
|
|
@ -49,7 +49,7 @@ Erg 的类型系统包含结构子类型 (SST)。 该系统类型化的类型称
|
|||
|
||||
Erg 可以将参数(类型参数)传递给类型定义。带有类型参数的 `Option`、`Array` 等称为多项式类型。这些本身不是类型,但它们通过应用参数成为类型。诸如 `Int`、`Str` 等没有参数的类型称为简单类型(标量类型)。
|
||||
|
||||
一个类型可以看成一个集合,并且存在包含关系。例如,“Num”包含“Add”、“Sub”等,“Int”包含“Nat”。
|
||||
一个类型可以看成一个集合,并且存在包含关系。例如,"Num"包含"Add"、"Sub"等,"Int"包含"Nat"。
|
||||
所有类的上类是`Object == Class {:}`,所有类型的下类是`Never == Class {}`。这在下面描述。
|
||||
|
||||
## 类型
|
||||
|
@ -86,7 +86,7 @@ lpop|T, N|(l: [T; N]): (T, [T; N-1]) =
|
|||
```
|
||||
|
||||
以 `!` 结尾的类型可以重写内部结构。 例如,`[T; !N]` 类是一个动态数组。
|
||||
要从“T”类型的对象创建“T!”类型的对象,请使用一元运算符“!”。
|
||||
要从"T"类型的对象创建"T!"类型的对象,请使用一元运算符"!"。
|
||||
|
||||
```python
|
||||
i: Int! = !1
|
||||
|
@ -112,7 +112,7 @@ Point2D = {.x = Int; .y = Int}
|
|||
|
||||
## 数据类型
|
||||
|
||||
如前所述,Erg 中的“类型”大致表示一组对象。
|
||||
如前所述,Erg 中的"类型"大致表示一组对象。
|
||||
|
||||
下面是 `Add` 类型的定义,需要 `+`(中间运算符)。 `R, O` 是所谓的类型参数,可以是真正的类型(类),例如 `Int` 或 `Str`。 在其他语言中,类型参数被赋予特殊的符号(泛型、模板等),但在 Erg 中,它们可以像普通参数一样定义。
|
||||
类型参数也可以用于类型对象以外的类型。 例如数组类型`[Int; 3]` 是 `Array Int, 3` 的语法糖。 如果类型实现重叠,用户必须明确选择一个。
|
||||
|
@ -184,7 +184,7 @@ Binary.
|
|||
1 -> True
|
||||
```
|
||||
|
||||
此后,代码“0.to_bool()”是可能的(尽管“0 as Bool == False”是内置定义的)。
|
||||
此后,代码"0.to_bool()"是可能的(尽管"0 as Bool == False"是内置定义的)。
|
||||
这是一个实际上可以重写 `self` 的类型的示例,如代码所示。
|
||||
|
||||
```python
|
||||
|
@ -219,7 +219,7 @@ add l: Add, r: Add =
|
|||
l + r # 类型错误: `_+_` 没有实现: |T, U <: Add| (T, U) -> <失败>
|
||||
```
|
||||
|
||||
此外,下面的类型 `A` 和 `B` 不被认为是同一类型。 但是,类型“O”被认为是匹配的
|
||||
此外,下面的类型 `A` 和 `B` 不被认为是同一类型。 但是,类型"O"被认为是匹配的
|
||||
|
||||
```python
|
||||
... |R1; R2; O; A <: Add(R1, O); B <: Add(R2, O)|
|
||||
|
|
|
@ -27,7 +27,7 @@ Point2D <: Norm # 类型错误:Point2D 不是 Norm 的子类型
|
|||
Point2D = Class {.x = Int; .y = Int}
|
||||
```
|
||||
|
||||
特征与结构类型一样,可以应用组合、替换和消除等操作(例如“T 和 U”)。 由此产生的特征称为即时特征。
|
||||
特征与结构类型一样,可以应用组合、替换和消除等操作(例如"T 和 U")。 由此产生的特征称为即时特征。
|
||||
|
||||
```python
|
||||
T = Trait {.x = Int}
|
||||
|
@ -51,7 +51,7 @@ assert points.iter().map(x -> x.norm()).collect(Array) == [5, 25].
|
|||
|
||||
扩展运算符 `...` 允许您将包含某个特征的特征定义为超类型。 这称为特征的 __subsumption__。
|
||||
在下面的示例中,`BinAddSub` 包含 `BinAdd` 和 `BinSub`。
|
||||
这对应于类中的继承,但与继承不同的是,可以使用“和”组合多个基类型。 也允许被 `not` 部分排除的特征。
|
||||
这对应于类中的继承,但与继承不同的是,可以使用"和"组合多个基类型。 也允许被 `not` 部分排除的特征。
|
||||
|
||||
```python
|
||||
Add R = Trait {
|
||||
|
@ -102,7 +102,7 @@ C.
|
|||
`_+_` self, other: Self = Self.new {i = self::i + other::i}
|
||||
|
||||
add C.new(1), C.new(2) # 类型错误:C 不是 Add 的子类
|
||||
# 提示:继承或修补“添加”
|
||||
# 提示:继承或修补"添加"
|
||||
```
|
||||
|
||||
不需要为此实现声明结构特征,但类型推断不起作用。 使用时需要指定类型。
|
||||
|
|
|
@ -16,7 +16,7 @@ print! john # <Person object>
|
|||
print! classof(john) # Person
|
||||
```
|
||||
|
||||
赋予“Class”的类型(通常是记录类型)称为需求类型(在本例中为“{.name = Str; .age = Nat}”)。
|
||||
赋予"Class"的类型(通常是记录类型)称为需求类型(在本例中为"{.name = Str; .age = Nat}")。
|
||||
可以使用 `<Class name>::__new__ {<attribute name> = <value>; 创建实例 ...}` 可以创建。
|
||||
`{.name = "约翰·史密斯"; .age = 25}` 只是一条记录,但它通过传递 `Person.new` 转换为 `Person` 实例。
|
||||
创建此类实例的子例程称为构造函数。
|
||||
|
@ -59,7 +59,7 @@ Person = Class {
|
|||
|
||||
元素属性(在记录中定义的属性)和类型属性(也称为实例/类属性,尤其是在类的情况下)是完全不同的东西。 类型属性是类型本身的属性。 当一个类型的元素本身没有所需的属性时,它指的是一个类型属性。 元素属性是元素直接拥有的唯一属性。
|
||||
为什么要进行这种区分? 如果所有属性都是元素属性,那么在创建对象时复制和初始化所有属性将是低效的。
|
||||
此外,以这种方式划分属性明确了诸如“该属性是共享的”和“该属性是分开持有的”之类的角色。
|
||||
此外,以这种方式划分属性明确了诸如"该属性是共享的"和"该属性是分开持有的"之类的角色。
|
||||
|
||||
下面的例子说明了这一点。 `species` 属性对所有实例都是通用的,因此将其用作类属性更自然。 但是,属性 `name` 应该是实例属性,因为每个实例都应该单独拥有它。
|
||||
|
||||
|
@ -97,12 +97,12 @@ C.i = 1 # 属性错误:`.i` 已在实例字段中定义
|
|||
请注意,`1` 的类和类型是不同的。
|
||||
只有一个类 `Int` 是 `1` 的生成器。 可以通过`classof(obj)`或`obj.__class__`获取对象所属的类。
|
||||
相比之下,`1`有无数种。 例如,`{1}, {0, 1}, 0..12, Nat, Int, Num`。
|
||||
但是,可以将最小类型定义为单一类型,在本例中为“{1}”。 可以通过`Typeof(obj)`获取对象所属的类型。 这是一个编译时函数。
|
||||
但是,可以将最小类型定义为单一类型,在本例中为"{1}"。 可以通过`Typeof(obj)`获取对象所属的类型。 这是一个编译时函数。
|
||||
对象可以使用补丁方法以及类方法。
|
||||
Erg 不允许您添加类方法,但您可以使用 [patch](./07_patch.md) 来扩展类。
|
||||
|
||||
您还可以从现有类([Inheritable](./../27_decorator.md/#inheritable) 类)继承。
|
||||
您可以使用 `Inherit` 创建一个继承类。 左侧的类型称为派生类,右侧的“继承”的参数类型称为基类(继承类)。
|
||||
您可以使用 `Inherit` 创建一个继承类。 左侧的类型称为派生类,右侧的"继承"的参数类型称为基类(继承类)。
|
||||
|
||||
```python
|
||||
MyStr = Inherit Str
|
||||
|
@ -251,7 +251,7 @@ assert e ! = f
|
|||
|
||||
## 枚举类
|
||||
|
||||
为了便于定义“Or”类型的类,提供了一个“Enum”。
|
||||
为了便于定义"Or"类型的类,提供了一个"Enum"。
|
||||
|
||||
```python
|
||||
X = Class()
|
||||
|
|
|
@ -29,7 +29,7 @@ alice = Student.new {name = "Alice", id = 123}
|
|||
MailAddress = Inherit Str, additional: {owner = Str} # 类型错误:实例变量不能添加到值类中
|
||||
```
|
||||
|
||||
Erg 的特殊设计不允许继承“Never”类型。 Erg 的特殊设计不允许继承 `Never` 类型,因为 `Never` 是一个永远无法实例化的独特类。
|
||||
Erg 的特殊设计不允许继承"Never"类型。 Erg 的特殊设计不允许继承 `Never` 类型,因为 `Never` 是一个永远无法实例化的独特类。
|
||||
|
||||
## 枚举类的继承
|
||||
|
||||
|
@ -60,7 +60,7 @@ StrMoreThan4 = Inherit StrMoreThan3, Excluding: StrWithLen N | N == 3
|
|||
|
||||
## 覆盖
|
||||
|
||||
该类与补丁相同,可以将新方法添加到原始类型,但可以进一步“覆盖”该类。
|
||||
该类与补丁相同,可以将新方法添加到原始类型,但可以进一步"覆盖"该类。
|
||||
这种覆盖称为覆盖。要覆盖,必须满足三个条件。
|
||||
首先,覆盖必须有一个 `Override` 装饰器,因为默认情况下它会导致错误。
|
||||
另外,覆盖不能改变方法的类型。它必须是原始类型的子类型。
|
||||
|
@ -68,7 +68,7 @@ StrMoreThan4 = Inherit StrMoreThan3, Excluding: StrWithLen N | N == 3
|
|||
|
||||
为什么这个条件是必要的?这是因为重写不仅会改变一种方法的行为,而且可能会影响另一种方法的行为。
|
||||
|
||||
让我们从第一个条件开始。此条件是为了防止“意外覆盖”。
|
||||
让我们从第一个条件开始。此条件是为了防止"意外覆盖"。
|
||||
换句话说,必须使用 `Override` 装饰器来防止派生类中新定义的方法的名称与基类的名称冲突。
|
||||
|
||||
接下来,考虑第二个条件。这是为了类型一致性。由于派生类是基类的子类型,因此它的行为也必须与基类的行为兼容。
|
||||
|
@ -150,7 +150,7 @@ IntAndStr = Inherit Int and Str # 语法错误:不允许类的多重继承
|
|||
## 多层(多级)继承
|
||||
|
||||
Erg 继承也禁止多层继承。 也就是说,您不能定义从另一个类继承的类。
|
||||
从“Object”继承的可继承类可能会异常继承。
|
||||
从"Object"继承的可继承类可能会异常继承。
|
||||
|
||||
同样在这种情况下,可以使用 Python 的多层继承类。
|
||||
|
||||
|
@ -204,11 +204,11 @@ Inherited!
|
|||
## 使用继承
|
||||
|
||||
虽然继承在正确使用时是一项强大的功能,但它也有一个缺点,即它往往会使类依赖关系复杂化,尤其是在使用多层或多层继承时。复杂的依赖关系会降低代码的可维护性。
|
||||
Erg 禁止多重和多层继承的原因是为了降低这种风险,并且引入了类补丁功能以降低依赖关系的复杂性,同时保留继承的“添加功能”方面。
|
||||
Erg 禁止多重和多层继承的原因是为了降低这种风险,并且引入了类补丁功能以降低依赖关系的复杂性,同时保留继承的"添加功能"方面。
|
||||
|
||||
那么,反过来说,应该在哪里使用继承呢?一个指标是何时需要“基类的语义子类型”。
|
||||
那么,反过来说,应该在哪里使用继承呢?一个指标是何时需要"基类的语义子类型"。
|
||||
Erg 允许类型系统自动进行部分子类型确定(例如,Nat,其中 Int 大于或等于 0)。
|
||||
但是,例如,仅依靠 Erg 的类型系统很难创建“表示有效电子邮件地址的字符串类型”。您可能应该对普通字符串执行验证。然后,我们想为已通过验证的字符串对象添加某种“保证”。这相当于向下转换为继承的类。将 `Str object` 向下转换为 `ValidMailAddressStr` 与验证字符串是否采用正确的电子邮件地址格式是一一对应的。
|
||||
但是,例如,仅依靠 Erg 的类型系统很难创建"表示有效电子邮件地址的字符串类型"。您可能应该对普通字符串执行验证。然后,我们想为已通过验证的字符串对象添加某种"保证"。这相当于向下转换为继承的类。将 `Str object` 向下转换为 `ValidMailAddressStr` 与验证字符串是否采用正确的电子邮件地址格式是一一对应的。
|
||||
|
||||
```python
|
||||
ValidMailAddressStr = Inherit Str
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Erg 不允许修改现有类型和类。
|
||||
这意味着,不可能在类中定义额外的方法,也不能执行特化(一种语言特性,单态化多态声明的类型并定义专用方法,如在 C++ 中)。
|
||||
但是,在许多情况下,您可能希望向现有类型或类添加功能,并且有一个称为“修补”的功能允许您执行此操作。
|
||||
但是,在许多情况下,您可能希望向现有类型或类添加功能,并且有一个称为"修补"的功能允许您执行此操作。
|
||||
|
||||
```python
|
||||
StrReverse = Patch Str
|
||||
|
@ -120,7 +120,7 @@ StrReverse.
|
|||
```
|
||||
|
||||
每个类型/特征对只能定义一个胶水补丁。
|
||||
这是因为如果多个胶水修复程序同时“可见”,就不可能唯一确定选择哪个实现。
|
||||
这是因为如果多个胶水修复程序同时"可见",就不可能唯一确定选择哪个实现。
|
||||
但是,当移动到另一个范围(模块)时,您可以交换维修程序。
|
||||
|
||||
```python
|
||||
|
@ -131,7 +131,7 @@ NumericStr.
|
|||
NumStrRev = Patch NumericStr, Impl := Reverse
|
||||
NumStrRev.
|
||||
...
|
||||
# 重复修补程序错误:数值Str已与“反向”关联`
|
||||
# 重复修补程序错误:数值Str已与"反向"关联`
|
||||
# 提示:'Str'(NumericStr'的超类)通过'StrReverse'与'Reverse'关联
|
||||
```
|
||||
|
||||
|
@ -187,7 +187,7 @@ fn iter<I>(i: I) -> impl Iterator<Item = I::Item> where I: IntoIterator {
|
|||
|
||||
## 通用补丁
|
||||
|
||||
补丁不仅可以为一种特定类型定义,还可以为“一般功能类型”等定义。
|
||||
补丁不仅可以为一种特定类型定义,还可以为"一般功能类型"等定义。
|
||||
在这种情况下,要给出自由度的项作为参数给出(在下面的情况下,`T:Type`)。 以这种方式定义的补丁称为全对称补丁。
|
||||
如您所见,全对称补丁正是一个返回补丁的函数,但它本身也可以被视为补丁。
|
||||
|
||||
|
|
|
@ -36,4 +36,4 @@ Value = (
|
|||
|
||||
---
|
||||
|
||||
<span id="1" style="font-size:x-small"><sup>1</sup> Erg 中的术语“值类型”与其他语言中的定义不同。 纯 Erg 语义中没有内存的概念,并且因为它被放置在堆栈上而说它是值类型,或者因为它实际上是一个指针而说它不是值类型是不正确的。 值类型仅表示它是“值”类型或其子类型。 [↩](#f1)</span>
|
||||
<span id="1" style="font-size:x-small"><sup>1</sup> Erg 中的术语"值类型"与其他语言中的定义不同。 纯 Erg 语义中没有内存的概念,并且因为它被放置在堆栈上而说它是值类型,或者因为它实际上是一个指针而说它不是值类型是不正确的。 值类型仅表示它是"值"类型或其子类型。 [↩](#f1)</span>
|
||||
|
|
|
@ -31,7 +31,7 @@ e = 10..<0 # 语法错误
|
|||
f = 10<..<0 # 语法错误
|
||||
```
|
||||
|
||||
Range 运算符可用于非数字类型,只要它们是“Ord”不可变类型
|
||||
Range 运算符可用于非数字类型,只要它们是"Ord"不可变类型
|
||||
|
||||
```python
|
||||
Alphabet = "A".."z"
|
||||
|
|
|
@ -65,7 +65,7 @@ ExtraStatus = Trait {"Ok", "Error", "Unknown"}
|
|||
|
||||
方法也可以通过补丁添加。
|
||||
|
||||
使用“或”运算符明确指示包含或向现有 Enum 类型添加选项。
|
||||
使用"或"运算符明确指示包含或向现有 Enum 类型添加选项。
|
||||
|
||||
```python
|
||||
ExtraStatus = Status or {"Unknown"}
|
||||
|
|
|
@ -53,7 +53,7 @@ match i:
|
|||
log "i: Nat"
|
||||
```
|
||||
|
||||
但是,Erg 目前无法做出诸如“偶数”之类的子决策,因为它不是“奇数”等。
|
||||
但是,Erg 目前无法做出诸如"偶数"之类的子决策,因为它不是"奇数"等。
|
||||
|
||||
## 枚举、区间和筛选类型
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
## 联合(Union)
|
||||
|
||||
联合类型可以为类型提供多种可能性。 顾名思义,它们是由“或”运算符生成的。
|
||||
联合类型可以为类型提供多种可能性。 顾名思义,它们是由"或"运算符生成的。
|
||||
一个典型的 Union 是 `Option` 类型。 `Option` 类型是 `T 或 NoneType` 补丁类型,主要表示可能失败的值。
|
||||
|
||||
```python
|
||||
|
@ -27,7 +27,7 @@ Option T = T or NoneType
|
|||
Num = Add and Sub and Mul and Eq
|
||||
```
|
||||
|
||||
如上所述,普通类不能与“and”操作结合使用。 这是因为实例只属于一个类。
|
||||
如上所述,普通类不能与"and"操作结合使用。 这是因为实例只属于一个类。
|
||||
|
||||
## 差异
|
||||
|
||||
|
@ -45,7 +45,7 @@ OneTwoThree = {1, 2, 3, 4, 5, 6} - {4, 5, 6, 7, 8, 9, 10}
|
|||
## 补充
|
||||
|
||||
补码类型是通过 `not` 操作得到的,这是一个一元操作。 `not T` 类型是 `{=} not T` 的简写。
|
||||
类型为“非 T”的交集等价于 Diff,类型为“非 T”的 Diff 等价于交集。
|
||||
类型为"非 T"的交集等价于 Diff,类型为"非 T"的 Diff 等价于交集。
|
||||
但是,不推荐这种写法。
|
||||
|
||||
```python
|
||||
|
@ -59,7 +59,7 @@ Bool == {True} not not {False} # 2 == 1 - -1
|
|||
## 真代数类型
|
||||
|
||||
有两种代数类型:可以简化的表观代数类型和不能进一步简化的真实代数类型。
|
||||
“表观代数类型”包括 Enum、Interval 和 Record 类型的 `or` 和 `and`。
|
||||
"表观代数类型"包括 Enum、Interval 和 Record 类型的 `or` 和 `and`。
|
||||
这些不是真正的代数类型,因为它们被简化了,并且将它们用作类型说明符将导致警告; 要消除警告,您必须简化它们或定义它们的类型。
|
||||
|
||||
```python
|
||||
|
@ -76,7 +76,7 @@ Point2D = Point1D and {y = Int; ...} # == {x = Int; y = Int; ...}
|
|||
q: Point2D = {x = 1; y = 2; z = 3}
|
||||
```
|
||||
|
||||
真正的代数类型包括类型“或”和“与”。 类之间的“或”等类属于“或”类型。
|
||||
真正的代数类型包括类型"或"和"与"。 类之间的"或"等类属于"或"类型。
|
||||
|
||||
```python
|
||||
assert Int or Str == Or(Int, Str)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
依赖类型是将值作为参数的类型。 普通的多态类型只能将类型作为参数,但依赖类型放宽了这个限制。
|
||||
|
||||
依赖类型等价于`[T; N]`(`数组(T,N)`)。
|
||||
这种类型不仅取决于内容类型“T”,还取决于内容数量“N”。 `N` 包含一个`Nat` 类型的对象。
|
||||
这种类型不仅取决于内容类型"T",还取决于内容数量"N"。 `N` 包含一个`Nat` 类型的对象。
|
||||
|
||||
```python
|
||||
a1 = [1, 2, 3]
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
id x: Int = x
|
||||
```
|
||||
|
||||
返回输入的“id”函数是为“Int”类型定义的,但这个函数显然可以为任何类型定义。
|
||||
返回输入的"id"函数是为"Int"类型定义的,但这个函数显然可以为任何类型定义。
|
||||
让我们使用 `Object` 来表示最大的类。
|
||||
|
||||
```python
|
||||
|
@ -21,7 +21,7 @@ b = id True
|
|||
```
|
||||
|
||||
当然,它现在接受任意类型,但有一个问题:返回类型被扩展为 `Object`。 返回类型扩展为 `Object`。
|
||||
如果输入是“Int”类型,我想查看返回类型“Int”,如果输入是“Str”类型,我想查看“Str”。
|
||||
如果输入是"Int"类型,我想查看返回类型"Int",如果输入是"Str"类型,我想查看"Str"。
|
||||
|
||||
```python
|
||||
print! id 1 # <Object object>
|
||||
|
@ -52,7 +52,7 @@ id x: NoneType = x
|
|||
...
|
||||
```
|
||||
|
||||
此外,类型变量“T”可以推断为“Type”类型,因为它在类型规范中使用。 所以 `|T: Type|` 可以简单地缩写为 `|T|`。
|
||||
此外,类型变量"T"可以推断为"Type"类型,因为它在类型规范中使用。 所以 `|T: Type|` 可以简单地缩写为 `|T|`。
|
||||
你也可以省略`|T, N| 脚; N]` 如果可以推断它不是类型对象(`T: Type, N: Nat`)。
|
||||
|
||||
如果类型对于任意类型来说太大,您也可以提供约束。
|
||||
|
@ -66,7 +66,7 @@ add|T <: Add| l: T, r: T = l + r
|
|||
```
|
||||
|
||||
在本例中,`T` 必须是`Add` 类型的子类,并且要分配的`l` 和`r` 的实际类型必须相同。
|
||||
在这种情况下,“T”由“Int”、“Ratio”等满足。因此,例如,“Int”和“Str”的添加没有定义,因此被拒绝。
|
||||
在这种情况下,"T"由"Int"、"Ratio"等满足。因此,例如,"Int"和"Str"的添加没有定义,因此被拒绝。
|
||||
|
||||
您也可以像这样键入它。
|
||||
|
||||
|
@ -203,9 +203,9 @@ K(0).
|
|||
print! classof(id) # |T: Type| T -> T
|
||||
```
|
||||
|
||||
我们得到一个类型`|T: Type| T -> T`。 这称为一个 __封闭的全称量化类型/全称类型__,即`['a. ...]'` 在 ML 和 `forall t. ...` 在 Haskell 中。 为什么使用形容词“关闭”将在下面讨论。
|
||||
我们得到一个类型`|T: Type| T -> T`。 这称为一个 __封闭的全称量化类型/全称类型__,即`['a. ...]'` 在 ML 和 `forall t. ...` 在 Haskell 中。 为什么使用形容词"关闭"将在下面讨论。
|
||||
|
||||
封闭的全称量化类型有一个限制:只有子程序类型可以被通用量化,即只有子程序类型可以放在左子句中。 但这已经足够了,因为子程序是 Erg 中最基本的控制结构,所以当我们说“我要处理任意 X”时,即我想要一个可以处理任意 X 的子程序。所以,量化类型具有相同的含义 作为多态函数类型。 从现在开始,这种类型基本上被称为多态函数类型。
|
||||
封闭的全称量化类型有一个限制:只有子程序类型可以被通用量化,即只有子程序类型可以放在左子句中。 但这已经足够了,因为子程序是 Erg 中最基本的控制结构,所以当我们说"我要处理任意 X"时,即我想要一个可以处理任意 X 的子程序。所以,量化类型具有相同的含义 作为多态函数类型。 从现在开始,这种类型基本上被称为多态函数类型。
|
||||
|
||||
与匿名函数一样,多态类型具有任意类型变量名称,但它们都具有相同的值。
|
||||
|
||||
|
@ -222,7 +222,7 @@ assert (|T: Type| T -> T) == (|U: Type| U -> U)
|
|||
类型变量在左侧定义并在右侧使用的类型,例如 `OpenFn T: Type = T -> T`,称为 __open 通用类型__。
|
||||
相反,在右侧定义和使用类型变量的类型,例如 `ClosedFn = |T: Type| T -> T`,被称为 __封闭的通用类型__。
|
||||
|
||||
开放通用类型是所有同构“真”类型的超类型。 相反,封闭的通用类型是所有同构真类型的子类型。
|
||||
开放通用类型是所有同构"真"类型的超类型。 相反,封闭的通用类型是所有同构真类型的子类型。
|
||||
|
||||
```python
|
||||
(|T: Type| T -> T) < (Int -> Int) < (T -> T)
|
||||
|
@ -270,7 +270,7 @@ id_int_fn(f3: Int -> Int): (Int -> Int) = f
|
|||
```python
|
||||
PolyFn = Patch(|T| T -> T)
|
||||
PolyFn.
|
||||
type self = T # 名称错误:找不到“T”
|
||||
type self = T # 名称错误:找不到"T"
|
||||
DepFn T = Patch(T -> T)
|
||||
DepFn.
|
||||
type self =
|
||||
|
|
|
@ -54,7 +54,7 @@ assert not c in D
|
|||
|
||||
子例程的参数和返回值只采用一个类。
|
||||
换句话说,您不能直接将结构类型或特征指定为函数的类型。
|
||||
必须使用部分类型规范将其指定为“作为该类型子类型的单个类”。
|
||||
必须使用部分类型规范将其指定为"作为该类型子类型的单个类"。
|
||||
|
||||
```python
|
||||
# OK
|
||||
|
|
|
@ -62,7 +62,7 @@ assert 1.into<Ratio>() == 1.0
|
|||
|
||||
## 向下转型
|
||||
|
||||
由于向下转换通常是不安全的并且转换方法很重要,我们改为实现“TryFrom.try_from”
|
||||
由于向下转换通常是不安全的并且转换方法很重要,我们改为实现"TryFrom.try_from"
|
||||
|
||||
```python
|
||||
IntTryFromFloat = Patch Int
|
||||
|
|
|
@ -14,7 +14,7 @@ Person!.
|
|||
inc_age!ref!self = self::name.update!old -> old + 1
|
||||
```
|
||||
|
||||
准确地说,基类型是可变类型或包含可变类型的复合类型的类型必须在类型名称的末尾有一个“!”。 没有 `!` 的类型可以存在于同一个命名空间中,并被视为单独的类型。
|
||||
准确地说,基类型是可变类型或包含可变类型的复合类型的类型必须在类型名称的末尾有一个"!"。 没有 `!` 的类型可以存在于同一个命名空间中,并被视为单独的类型。
|
||||
在上面的例子中,`.age` 属性是可变的,`.name` 属性是不可变的。 如果即使一个属性是可变的,那么整个属性也是可变的。
|
||||
|
||||
可变类型可以定义重写实例的过程方法,但具有过程方法并不一定使它们可变。 例如数组类型`[T; N]` 实现了一个 `sample!` 随机选择一个元素的方法,但当然不会破坏性地修改数组。
|
||||
|
@ -42,7 +42,7 @@ a = [1, 2, 3].into [Nat; !3]
|
|||
x = a.freeze_map a: [Nat; 3] -> a.iter().map(i -> i + 1).filter(i -> i % 2 == 0).collect(Array)
|
||||
```
|
||||
|
||||
在多态不可变类型中,该类型的类型参数“T”被隐式假定为不可变。
|
||||
在多态不可变类型中,该类型的类型参数"T"被隐式假定为不可变。
|
||||
|
||||
```python
|
||||
# ImmutType < Type
|
||||
|
|
|
@ -17,7 +17,7 @@ List.
|
|||
{nil; cons; ...} = List
|
||||
|
||||
print! cons(1, cons(2, nil())).head() # 1
|
||||
print! nil.head() # 运行时错误:“空list”
|
||||
print! nil.head() # 运行时错误:"空list"
|
||||
```
|
||||
|
||||
我们说 `List.nil|T|() = ...` 而不是 `List(T).nil() = ...` 的原因是我们在使用它时不需要指定类型。
|
||||
|
|
|
@ -25,7 +25,7 @@ arr.map i -> i + 1
|
|||
上面代码中的 `arr` 和 `i` 是不同作用域的变量。 因此,每个寿命都是不同的(`i` 更短)。
|
||||
|
||||
到目前为止,所有类型变量的类型都具有相同的生命周期。 换句话说,‘T’、‘X’和‘Y’必须同时确定,之后保持不变。
|
||||
反之,如果我们可以将 `T` 视为“内部作用域”中的类型变量,我们可以组成一个 `tuple_map` 函数。 __Rank 2 type__ 就是为此目的而准备的。
|
||||
反之,如果我们可以将 `T` 视为"内部作用域"中的类型变量,我们可以组成一个 `tuple_map` 函数。 __Rank 2 type__ 就是为此目的而准备的。
|
||||
|
||||
```python
|
||||
# tuple_map: ((|T: Type| T -> T), (Int, Str)) -> (Int, Str)
|
||||
|
@ -88,18 +88,18 @@ assert f2 == g2
|
|||
开放的多相关函数类型具体称为 __任意函数类型__。 任意函数类型有无数种可能性:`Int -> Int`、`Str -> Str`、`Bool -> Bool`、`|T: Type| T -> T`, ... 是。
|
||||
另一方面,只有一个封闭的(返回与参数相同类型的对象)多态类型`|T:Type| T -> T`。 这种类型被专门称为 __多态函数类型__。
|
||||
也就是说,`f1`可以通过`x: Int -> x+1`、`x: Bool -> not x`、`x -> x`等=`f1`是一个多相关数是的,但是您只能将 `x -> x` 等传递给 `f2` = `f2` 不是 __多元相关__。
|
||||
但是像`f2`这样的函数类型明显不同于普通类型,我们需要新的概念来处理它们。 那是类型的“等级”。
|
||||
但是像`f2`这样的函数类型明显不同于普通类型,我们需要新的概念来处理它们。 那是类型的"等级"。
|
||||
|
||||
关于rank的定义,没有量化的类型,如`Int`、`Str`、`Bool`、`T`、`Int -> Int`、`Option Int`等,都被视为“rank” 0”。
|
||||
关于rank的定义,没有量化的类型,如`Int`、`Str`、`Bool`、`T`、`Int -> Int`、`Option Int`等,都被视为"rank" 0"。
|
||||
|
||||
```python
|
||||
# K 是多项式类型,例如 Option
|
||||
R0 = (Int or Str or Bool or ...) or (R0 -> R0) or K(R0)
|
||||
```
|
||||
|
||||
接下来,具有一阶全称的类型,例如`|T| T -> T`,或者在返回值类型中包含它们的类型是“rank 1”。
|
||||
此外,具有二阶全称量化的类型(具有 rank 1 类型作为参数的类型,例如 `(|T| T -> T) -> Int`)或将它们包含在返回类型中的类型称为“rank 2 ”。
|
||||
重复上述以定义“Rank N”类型。 此外,秩-N 类型包括秩为N 或更少的所有类型。 因此,混合等级的类型与其中最高的等级相同。
|
||||
接下来,具有一阶全称的类型,例如`|T| T -> T`,或者在返回值类型中包含它们的类型是"rank 1"。
|
||||
此外,具有二阶全称量化的类型(具有 rank 1 类型作为参数的类型,例如 `(|T| T -> T) -> Int`)或将它们包含在返回类型中的类型称为"rank 2 "。
|
||||
重复上述以定义"Rank N"类型。 此外,秩-N 类型包括秩为N 或更少的所有类型。 因此,混合等级的类型与其中最高的等级相同。
|
||||
|
||||
```python
|
||||
R1 = (|...| R0) or (R0 -> R1) or K(R1) or R0
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/advanced/kind.md&commit_hash=14657486719a134f494e107774ac8f9d5a63f083)
|
||||
|
||||
一切都在 Erg 中输入。类型本身也不例外。 __kind__ 表示“类型的类型”。例如,`Int` 属于 `Type`,就像 `1` 属于 `Int`。 `Type` 是最简单的一种,__atomic kind__。在类型论符号中,`Type` 对应于 `*`。
|
||||
一切都在 Erg 中输入。类型本身也不例外。 __kind__ 表示"类型的类型"。例如,`Int` 属于 `Type`,就像 `1` 属于 `Int`。 `Type` 是最简单的一种,__atomic kind__。在类型论符号中,`Type` 对应于 `*`。
|
||||
|
||||
在Kind的概念中,实际上重要的是一种或多种Kind(多项式Kind)。单项类型,例如`Option`,属于它。一元Kind表示为 `Type -> Type` [<sup id="f1">1</sup>](#1)。诸如 `Array` 或 `Option` 之类的 __container__ 特别是一种以类型作为参数的多项式类型。
|
||||
正如符号 `Type -> Type` 所表明的,`Option` 实际上是一个接收类型 `T` 并返回类型 `Option T` 的函数。但是,由于这个函数不是通常意义上的函数,所以通常称为一元类。
|
||||
|
@ -82,7 +82,7 @@ assert IntContainerOf in (Type -> Type) -> Type
|
|||
assert {x = 1; y = 2} in {x = Int; y = Int}
|
||||
```
|
||||
|
||||
记录类型键入记录。 一个好的猜测者可能认为应该有一个“记录类型”来键入记录类型。 实际上它是存在的。
|
||||
记录类型键入记录。 一个好的猜测者可能认为应该有一个"记录类型"来键入记录类型。 实际上它是存在的。
|
||||
|
||||
```python
|
||||
log Typeof {x = Int; y = Int} # {{x = Int; y = Int}}
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
标记特征是没有必需属性的特征。 也就是说,您可以在不实现任何方法的情况下实现 Impl。
|
||||
没有 required 属性似乎没有意义,但由于注册了它属于 trait 的信息,因此可以使用 patch 方法或由编译器进行特殊处理。
|
||||
|
||||
所有标记特征都包含在“标记”特征中。
|
||||
作为标准提供的“光”是一种标记特征。
|
||||
所有标记特征都包含在"标记"特征中。
|
||||
作为标准提供的"光"是一种标记特征。
|
||||
|
||||
```python
|
||||
Light = Subsume Marker
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
```python
|
||||
Particle!State: {"base", "excited"}! = Class(... Impl := Phantom State)
|
||||
Particle!
|
||||
# 此方法将状态从“base”移动到“excited”
|
||||
# 此方法将状态从"base"移动到"excited"
|
||||
apply_electric_field!(ref! self("base" ~> "excited"), field: Vector) = ...
|
||||
```
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/type/advanced/projection.md&commit_hash=51de3c9d5a9074241f55c043b9951b384836b258)
|
||||
|
||||
投影类型表示如下代码中的“Self.AddO”等类型。
|
||||
投影类型表示如下代码中的"Self.AddO"等类型。
|
||||
|
||||
```python
|
||||
Add R = Trait {
|
||||
|
@ -15,7 +15,7 @@ AddForInt.
|
|||
AddO = Int
|
||||
```
|
||||
|
||||
类型“Add(R)”可以说是定义了与某个对象的加法的类型。 由于方法应该是一个类型属性,`+` 类型声明应该写在缩进下面。
|
||||
类型"Add(R)"可以说是定义了与某个对象的加法的类型。 由于方法应该是一个类型属性,`+` 类型声明应该写在缩进下面。
|
||||
`Add` 类型的场景是声明 `.AddO = Type`,而 `.AddO` 类型的实体是一个投影类型,由一个作为 ` 子类型的类型持有 添加`。 例如,`Int.AddO = Int`、`Odd.AddO = Even`。
|
||||
|
||||
```python
|
||||
|
|
|
@ -9,7 +9,7 @@ NonNullStr = |N: Nat| StrWithLen N | N ! = 0 # 同 {S | N: Nat; S: StrWithLen N;
|
|||
NonEmptyArray = |N: Nat| [_; N | N > 0] # 同 {A | N: Nat; A: Array(_, N); N > 0}
|
||||
```
|
||||
|
||||
量化依赖类型的标准形式是“K(A, ... | Pred)”。 `K` 是类型构造函数,`A, B` 是类型参数,`Pred` 是条件表达式。
|
||||
量化依赖类型的标准形式是"K(A, ... | Pred)"。 `K` 是类型构造函数,`A, B` 是类型参数,`Pred` 是条件表达式。
|
||||
|
||||
作为左值的量化依赖类型只能在与原始类型相同的模块中定义方法。
|
||||
|
||||
|
|
|
@ -33,12 +33,12 @@ Erg 可以对多态类型进行子类型化,但有一些注意事项。
|
|||
这听起来很复杂,但正如我们之前看到的,如果将其应用于实际示例,这是一个合理的规则。
|
||||
如果您仍然不明白,请考虑以下内容。
|
||||
|
||||
Erg 的设计原则之一是“大输入类型,小输出类型”。这正是函数可变性的情况。
|
||||
Erg 的设计原则之一是"大输入类型,小输出类型"。这正是函数可变性的情况。
|
||||
看上面的规则,输入类型越大,整体类型越小。
|
||||
这是因为通用函数明显比专用函数少。
|
||||
而且输出类型越小,整体越小。
|
||||
|
||||
这样一来,上面的策略就相当于说“尽量减少函数的类型”。
|
||||
这样一来,上面的策略就相当于说"尽量减少函数的类型"。
|
||||
|
||||
## 不变性
|
||||
|
||||
|
@ -55,7 +55,7 @@ Erg 有另一个修改。它是不变的。
|
|||
|B :> T| K(B)
|
||||
```
|
||||
|
||||
在类型变量列表中,执行类型变量的__variant说明__。 在上述变体规范中,类型变量“A”被声明为“T”类型的任何子类,“B”类型被声明为“T”类型的任何超类。
|
||||
在类型变量列表中,执行类型变量的__variant说明__。 在上述变体规范中,类型变量"A"被声明为"T"类型的任何子类,"B"类型被声明为"T"类型的任何超类。
|
||||
在这种情况下,`T` 也称为 `A` 的上部类型和 `B` 的下部类型。
|
||||
|
||||
突变规范也可以重叠。
|
||||
|
@ -116,12 +116,12 @@ List T = Class {head = T; rest = Cons T}
|
|||
List(T).
|
||||
push|U :> T|(self, x: U): List T = Self. new {head = x; rest = self}
|
||||
upcast(self, U :> T): List U = self
|
||||
# 类型警告:`.push` 中的 `U` 不能接受除 `U == T` 之外的任何内容。 将“U”替换为“T”。
|
||||
# 类型警告:`.upcast` 中的 `U` 不能接受除 `U == T` 之外的任何内容。 将“U”替换为“T”。
|
||||
# 类型警告:`.push` 中的 `U` 不能接受除 `U == T` 之外的任何内容。 将"U"替换为"T"。
|
||||
# 类型警告:`.upcast` 中的 `U` 不能接受除 `U == T` 之外的任何内容。 将"U"替换为"T"。
|
||||
```
|
||||
|
||||
只有当 `U == T` 时,约束 `U <: T` 和修改规范`U :> T` 才满足。 所以这个称号没有多大意义。
|
||||
只有“向上转换使得 `U == T`” = “向上转换不会改变 `U` 的位置”实际上是允许的。
|
||||
只有"向上转换使得 `U == T`" = "向上转换不会改变 `U` 的位置"实际上是允许的。
|
||||
|
||||
##附录:用户定义类型的修改
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ FinalWrapper.
|
|||
## 想使用不是字符串的枚举类型
|
||||
|
||||
可以定义其他语言中常见的传统枚举类型(代数数据类型)如下
|
||||
如果您实现“单例”,则类和实例是相同的。
|
||||
如果您实现"单例",则类和实例是相同的。
|
||||
此外,如果您使用 `Enum`,则选择的类型会自动定义为重定向属性。
|
||||
|
||||
```python
|
||||
|
|
|
@ -62,14 +62,14 @@ successors = [] # 替代包(当一个包被弃用时)
|
|||
## 语义版本控制
|
||||
|
||||
Erg 包是基于 [语义版本控制](https://semver.org/lang/en/) 进行版本控制的。
|
||||
语义版本控制大致以“x.y.z”格式指定(x、y、z 是大于或等于 0 的整数)。
|
||||
语义版本控制大致以"x.y.z"格式指定(x、y、z 是大于或等于 0 的整数)。
|
||||
每个数字的含义如下。
|
||||
|
||||
* x:主要版本(更新破坏兼容性时增加 1)
|
||||
* y:次要版本(执行兼容更新时增加1(API添加,弃用等),错误修复等由补丁版本升级处理)
|
||||
* z:补丁版本(当进行小的更改以修复错误或保持兼容性时增加1,破坏兼容性的严重修复由主要版本升级处理)
|
||||
|
||||
但是,默认情况下,版本 `0.*.*` 中的更改始终是不兼容的。如果要在保持兼容性的同时升级,请在其后指定 `-compatible`(Erg 自己的规则)。例如,如果要在保持与 0.2.1 兼容的同时添加功能,即要升级到 0.3.0,则指定 0.3.0-compatible。如果您已修复错误,还请指定“0.2.2-compatible”。
|
||||
但是,默认情况下,版本 `0.*.*` 中的更改始终是不兼容的。如果要在保持兼容性的同时升级,请在其后指定 `-compatible`(Erg 自己的规则)。例如,如果要在保持与 0.2.1 兼容的同时添加功能,即要升级到 0.3.0,则指定 0.3.0-compatible。如果您已修复错误,还请指定"0.2.2-compatible"。
|
||||
该版本将被视为与以前的版本兼容。
|
||||
即使您想将 `0.*.*` 升级到 `1.0.0`,这仍然有效。也就是说,`1.0.0-compatible` 与之前的版本 `0.y.z` 兼容。
|
||||
|
||||
|
@ -88,9 +88,9 @@ Erg 包管理器与版本控制系统(例如 git)一起使用,以检测代码
|
|||
语义版本控制存在(至少)两个已知问题。
|
||||
首先,语义版本控制可能过于严格。
|
||||
使用语义版本控制,单个不兼容的 API 更改会增加整个包的主要版本。
|
||||
发生这种情况时,诸如“我想尝试一个新的 API,但我必须处理另一个不兼容的 API 更改,所以我不会升级”之类的事情。
|
||||
发生这种情况时,诸如"我想尝试一个新的 API,但我必须处理另一个不兼容的 API 更改,所以我不会升级"之类的事情。
|
||||
其次,语义版本控制可以承诺太多。
|
||||
如上一节所述,对 API 的“兼容更改”在理论上是不可证明的。如果您指定要使用版本为 `1.0.1` 的包,则可以在语义版本控制方面使用 `1.0.1` 和 `2.0.0` 之间的任何包(`1.0.0` 不能被使用,因为错误已被修复),但由于包开发人员无意使用 API,构建可能不会成功。
|
||||
如上一节所述,对 API 的"兼容更改"在理论上是不可证明的。如果您指定要使用版本为 `1.0.1` 的包,则可以在语义版本控制方面使用 `1.0.1` 和 `2.0.0` 之间的任何包(`1.0.0` 不能被使用,因为错误已被修复),但由于包开发人员无意使用 API,构建可能不会成功。
|
||||
|
||||
Erg 通过允许同时使用不同版本的包(通过重命名)解决了这个问题。这使得在部分引入 ver2 API 的同时继续使用 ver1 API 成为可能。
|
||||
此外,虽然这不是一个非常理想的状态,但如果只能使用 API 的某个次要版本而没有错误,则可以不理会它并继续前进到下一个版本。
|
||||
|
|
|
@ -22,22 +22,22 @@
|
|||
|
||||
就其本义而言,
|
||||
|
||||
* 符号:在源代码中实心编写的字符(符号、控制字符等除外),不是字符串对象(未包含在“”中)。符号在 Ruby、Lisp 等中作为原始类型存在,但在 Erg 中它们不被视为对象。
|
||||
* 符号:在源代码中实心编写的字符(符号、控制字符等除外),不是字符串对象(未包含在""中)。符号在 Ruby、Lisp 等中作为原始类型存在,但在 Erg 中它们不被视为对象。
|
||||
* 标识符:(并且可以)引用某个对象的符号,而不是保留字。例如,在 Python 中 class 和 def 不能用作标识符。由于 Erg 没有保留字,所以除了某些符号外,所有符号都可以用作标识符。
|
||||
* 名称:与标识符的含义几乎相同。它有时与 Erg 中的代数同义使用。
|
||||
* 代数名称:相当于Erg中的标识符。在 C 中,函数名称是标识符,而不是代数名称。 “代数”指的是语言特性本身,它允许您使用 `=`(变量赋值运算符)或 `=`(常量赋值运算符)来分配对象。
|
||||
* 代数名称:相当于Erg中的标识符。在 C 中,函数名称是标识符,而不是代数名称。 "代数"指的是语言特性本身,它允许您使用 `=`(变量赋值运算符)或 `=`(常量赋值运算符)来分配对象。
|
||||
|
||||
```python
|
||||
代数名称<:(名称==标识符)<:符号
|
||||
变量 + 常数 == 代数
|
||||
```
|
||||
|
||||
然而,应该称为“代数”的东西,往往被称为“变量”。这就是数学术语的效果。
|
||||
然而,应该称为"代数"的东西,往往被称为"变量"。这就是数学术语的效果。
|
||||
值内容可以改变的变量是可变变量,值内容不改变的变量是不可变变量。
|
||||
请注意,常量始终是不可变的。
|
||||
|
||||
Erg 中不使用代数名称和名称,使用统一标识符。
|
||||
但是,一般来说,具有 `v = 1` 的 `v` 称为“变量 v”,而具有 `C = 1` 的 `C` 称为“常量 C”。 .
|
||||
但是,一般来说,具有 `v = 1` 的 `v` 称为"变量 v",而具有 `C = 1` 的 `C` 称为"常量 C"。 .
|
||||
|
||||
## 属性、字段、属性
|
||||
|
||||
|
@ -46,7 +46,7 @@ Erg 中不使用代数名称和名称,使用统一标识符。
|
|||
## 应用程序,调用
|
||||
|
||||
为子例程对象提供参数并获得结果。
|
||||
使用呼叫。这是因为Application有“应用软件”的用法。
|
||||
使用呼叫。这是因为Application有"应用软件"的用法。
|
||||
|
||||
## 数组列表
|
||||
|
||||
|
|
|
@ -12,8 +12,8 @@
|
|||
|
||||
### log(x: Object, type: LogType = Info) -> None
|
||||
|
||||
在調試顯示中記錄“x”。 執行完成后匯總并顯示日志
|
||||
支持表情符號的終端根據“類型”添加前綴
|
||||
在調試顯示中記錄"x"。 執行完成后匯總并顯示日志
|
||||
支持表情符號的終端根據"類型"添加前綴
|
||||
|
||||
* type == Info: ??
|
||||
* type == Ok: ?
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/modules/unit.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
`unit` 模塊是將數值計算中經常使用的單位定義為類型的模塊。
|
||||
Erg 數值類型包括 `Nat`、`Int`、`Ratio` 等。但是,這些類型沒有關于“數字的含義”的信息,因此可以執行諸如添加米和碼之類的無意義計算。
|
||||
Erg 數值類型包括 `Nat`、`Int`、`Ratio` 等。但是,這些類型沒有關于"數字的含義"的信息,因此可以執行諸如添加米和碼之類的無意義計算。
|
||||
通過使用 `unit` 模塊,您可以避免錯誤,例如將不同單位的數字傳遞給函數。
|
||||
這樣的錯誤確實會發生,并且會導致諸如[由于錯誤的單位系統導致火星探測器丟失](http://www.sydrose.com/case100/287/)之類的嚴重錯誤。
|
||||
如果您希望代碼在進行數值計算時更加健壯,您應該使用此模塊。
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
## `unsafe!`
|
||||
|
||||
執行“不安全”過程。 就像 Rust 一樣,`Unsafe` API 不能直接調用,而是作為高階函數傳遞給這個過程。
|
||||
執行"不安全"過程。 就像 Rust 一樣,`Unsafe` API 不能直接調用,而是作為高階函數傳遞給這個過程。
|
||||
|
||||
```python
|
||||
unsound = import "unsound"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/special.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
特殊形式是不能在 Erg 類型系統中表達的運算符、子程序(等等)。它被`包圍,但實際上無法捕獲。
|
||||
此外,為方便起見,還出現了“Pattern”、“Body”和“Conv”等類型,但不存在此類類型。它的含義也取決于上下文。
|
||||
此外,為方便起見,還出現了"Pattern"、"Body"和"Conv"等類型,但不存在此類類型。它的含義也取決于上下文。
|
||||
|
||||
## `=`(pat: Pattern, body: Body) -> NoneType
|
||||
|
||||
|
@ -33,7 +33,7 @@ L = X: Int -> Class(...)
|
|||
print! L # <kind L>
|
||||
```
|
||||
|
||||
`=` 運算符的返回值為“未定義”。
|
||||
`=` 運算符的返回值為"未定義"。
|
||||
函數中的多個賦值和 `=` 會導致語法錯誤。
|
||||
|
||||
```python
|
||||
|
@ -103,7 +103,7 @@ match [1, 2, 3]:
|
|||
|
||||
## del(x: ...T) -> NoneType | T
|
||||
|
||||
刪除變量“x”。但是,無法刪除內置對象。
|
||||
刪除變量"x"。但是,無法刪除內置對象。
|
||||
|
||||
```python
|
||||
a = 1
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
## 對象系統
|
||||
|
||||
Trait 類相當于 Python 中的 ABC(抽象基類,接口)
|
||||
實例屬于1、True、“aaa”等。
|
||||
實例屬于1、True、"aaa"等。
|
||||
類是 Int、Bool、Str 等。
|
||||
|
||||
### 類型
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/classes/Option.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
表示“可能失敗”的類型。
|
||||
表示"可能失敗"的類型。
|
||||
|
||||
## 方法
|
||||
|
||||
|
|
|
@ -6,4 +6,4 @@
|
|||
Result T, E <: Error = Either T, E
|
||||
```
|
||||
|
||||
和 `Option` 一樣,它代表“一個可能失敗的值”,但它可以有失敗的上下文。 用法與`Either`幾乎相同。
|
||||
和 `Option` 一樣,它代表"一個可能失敗的值",但它可以有失敗的上下文。 用法與`Either`幾乎相同。
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[.md%26commit_hash%3D06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/traits/Div(R,O).md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
如果除以零沒有錯誤,請使用“SafeDiv”
|
||||
如果除以零沒有錯誤,請使用"SafeDiv"
|
||||
|
||||
```python
|
||||
Div R, O = Trait {
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/API/types/traits/Sample.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
具有“隨機”選擇實例的`sample`和`sample!`方法的特征。`sample`方法總是返回相同的實例,而`sample!`方法返回一個隨機實例,該實例隨調用而變化
|
||||
具有"隨機"選擇實例的`sample`和`sample!`方法的特征。`sample`方法總是返回相同的實例,而`sample!`方法返回一個隨機實例,該實例隨調用而變化
|
||||
|
||||
請注意,這是一個假設您想要一個適當的實例進行測試等的特征,并且它不一定是隨機的。 如果您想要隨機抽樣,請使用“隨機”模塊。
|
||||
請注意,這是一個假設您想要一個適當的實例進行測試等的特征,并且它不一定是隨機的。 如果您想要隨機抽樣,請使用"隨機"模塊。
|
||||
|
||||
所有主要的值類都實現了 `Sample`。它還在由“Sample”類組成的元組類型、記錄類型、Or類型和篩選類型中實現
|
||||
所有主要的值類都實現了 `Sample`。它還在由"Sample"類組成的元組類型、記錄類型、Or類型和篩選類型中實現
|
||||
|
||||
```python
|
||||
assert Int.sample() == 42
|
||||
|
|
|
@ -3,4 +3,4 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/compiler/TODO_hint.md&commit_hash=d15cbbf7b33df0f78a575cff9679d84c36ea3ab1)
|
||||
|
||||
* `x 未定義`(x 已被`Del` 刪除)=> `提示:在第 X 行刪除`
|
||||
*補丁方法重復:“提示:指定補丁(如`T.foo(1)`)或使用`Del`刪除任何`.foo`”
|
||||
*補丁方法重復:"提示:指定補丁(如`T.foo(1)`)或使用`Del`刪除任何`.foo`"
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
## 3. 類型檢查和推斷,轉換 `AST` -> `HIR` (compiler/lower.rs)
|
||||
|
||||
* `HIR` 有每個變量的類型信息。它是用于“高級中間表示”的。
|
||||
* `HIR` 有每個變量的類型信息。它是用于"高級中間表示"的。
|
||||
* `HIR` 只保存變量的類型,但這已經足夠了。在極端情況下,這是因為 Erg 只有轉換(或運算符)應用程序的參數對象。
|
||||
* `ASTLower` 可以用與`Parser` 和`Lexer` 相同的方式構造。
|
||||
* 如果沒有錯誤發生,`ASTLowerer::lower` 將輸出 `HIR` 和 `CompileWarnings` 的元組。
|
||||
|
|
|
@ -83,12 +83,12 @@ pub enum Type {
|
|||
如果內容直到最后都保持為 None ,它將是一個無法確定為具體類型的類型變量(當場)。例如,具有 `id x = x` 的 `x` 類型。
|
||||
我將這種狀態下的類型變量稱為 __Unbound 類型變量__(我不知道確切的術語)。另一方面,我們將分配了某種具體類型的變量稱為 __Linked 類型變量__。
|
||||
|
||||
兩者都是自由類型變量(該術語顯然以“自由變量”命名)。這些是編譯器用于推理的類型變量。它之所以有這樣一個特殊的名字,是因為它不同于程序員指定類型的類型變量,例如 `id: 'T -> 'T` 中的 `'T`。
|
||||
兩者都是自由類型變量(該術語顯然以"自由變量"命名)。這些是編譯器用于推理的類型變量。它之所以有這樣一個特殊的名字,是因為它不同于程序員指定類型的類型變量,例如 `id: 'T -> 'T` 中的 `'T`。
|
||||
|
||||
未綁定類型變量表示為`?T`、`?U`。在類型論的上下文中,經常使用 α 和 β,但這一種是用來簡化輸入的。
|
||||
請注意,這是出于一般討論目的而采用的表示法,實際上并未使用字符串標識符實現。
|
||||
|
||||
進入類型環境時,未綁定的類型變量 `Type::Var` 被替換為 `Type::MonoQuantVar`。這稱為 __quantified 類型變量__。這類似于程序員指定的類型變量,例如“T”。內容只是一個字符串,并沒有像自由類型變量那樣鏈接到具體類型的工具。
|
||||
進入類型環境時,未綁定的類型變量 `Type::Var` 被替換為 `Type::MonoQuantVar`。這稱為 __quantified 類型變量__。這類似于程序員指定的類型變量,例如"T"。內容只是一個字符串,并沒有像自由類型變量那樣鏈接到具體類型的工具。
|
||||
|
||||
用量化類型變量替換未綁定類型變量的操作稱為__generalization__(或泛化)。如果將其保留為未綁定類型變量,則類型將通過一次調用固定(例如,調用 `id True` 后,`id 1` 的返回類型將是 `Bool`),所以它必須是概括的。
|
||||
以這種方式,在類型環境中注冊了包含量化類型變量的通用定義。
|
||||
|
@ -114,7 +114,7 @@ inst 'T = ?T (?T ? Γ)
|
|||
此外,如果表達式是調用,則獲取返回類型的操作表示為 `subst_call_ret`。 第一個參數是參數類型列表,第二個參數是要分配的類型。
|
||||
|
||||
類型替換規則 `{?T --> X}` 意味著將 `?T` 和 `X` 重寫為相同類型。 此操作稱為 __Unification__。 `X` 也可以是類型變量。
|
||||
[單獨部分](./unification.md) 中描述了詳細的統一算法。 我們將統一操作表示為“統一”。
|
||||
[單獨部分](./unification.md) 中描述了詳細的統一算法。 我們將統一操作表示為"統一"。
|
||||
|
||||
```python
|
||||
unify(?T, Int) == Ok(()) # ?T == (Int)
|
||||
|
@ -128,7 +128,7 @@ subst_call_ret([X, Y], (?T, ?U) -> ?U) == Y
|
|||
## 半統一(semi-unification)
|
||||
|
||||
統一的一種變體稱為半統一(__Semi-unification__)。 這是更新類型變量約束以滿足子類型關系的操作。
|
||||
在某些情況下,類型變量可能是統一的,也可能不是統一的,因此稱為“半”統一。
|
||||
在某些情況下,類型變量可能是統一的,也可能不是統一的,因此稱為"半"統一。
|
||||
|
||||
例如,在參數分配期間會發生半統一。
|
||||
因為實際參數的類型必須是形式參數類型的子類型。
|
||||
|
@ -145,7 +145,7 @@ f(a)
|
|||
|
||||
## 泛化
|
||||
|
||||
泛化不是一項簡單的任務。 當涉及多個作用域時,類型變量的“級別管理”就變得很有必要了。
|
||||
泛化不是一項簡單的任務。 當涉及多個作用域時,類型變量的"級別管理"就變得很有必要了。
|
||||
為了看到層級管理的必要性,我們首先確認沒有層級管理的類型推斷會導致問題。
|
||||
推斷以下匿名函數的類型。
|
||||
|
||||
|
@ -164,7 +164,7 @@ x(: ?T) ->
|
|||
y
|
||||
```
|
||||
|
||||
首先要確定的是右值 x 的類型。 右值是一種“用途”,因此我們將其具體化。
|
||||
首先要確定的是右值 x 的類型。 右值是一種"用途",因此我們將其具體化。
|
||||
但是 x 的類型 `?T` 已經被實例化了,因為它是一個自由變量。 Yo`?T` 成為右值的類型。
|
||||
|
||||
```python
|
||||
|
@ -187,7 +187,7 @@ x(: ?T) ->
|
|||
y
|
||||
```
|
||||
|
||||
y 的類型現在是一個量化類型變量“T”。 在下一行中,立即使用 `y`。 具體的。
|
||||
y 的類型現在是一個量化類型變量"T"。 在下一行中,立即使用 `y`。 具體的。
|
||||
|
||||
```python
|
||||
x: ?T ->
|
||||
|
@ -205,7 +205,7 @@ x: ?T ->
|
|||
|
||||
并查看生成的整個表達式的類型。 `?T -> ?U`。
|
||||
但顯然這個表達式應該是`?T -> ?T`,所以我們知道推理有問題。
|
||||
發生這種情況是因為我們沒有“級別管理”類型變量。
|
||||
發生這種情況是因為我們沒有"級別管理"類型變量。
|
||||
|
||||
所以我們用下面的符號來介紹類型變量的層次。 級別表示為自然數。
|
||||
|
||||
|
|
|
@ -31,5 +31,5 @@ a = [1, 2, 3].iter().map i -> i + 1
|
|||
r = {x = 1; y = 2}
|
||||
```
|
||||
|
||||
左側和右側值的精確定義是“如果它是可評估的,則為右側值,否則為左側值”。
|
||||
左側和右側值的精確定義是"如果它是可評估的,則為右側值,否則為左側值"。
|
||||
例如,考慮代碼 ``i = 1; i``,其中第二個 `i` 是右側值,因為它是可評估的,但第一個 `i` 是左側值。
|
|
@ -39,12 +39,12 @@ provided_method_table = {
|
|||
}
|
||||
```
|
||||
|
||||
具有 `.times` 方法的類型是 `Nat`、`Foo`。從這些中,找到與“{1}”類型匹配的一個。
|
||||
具有 `.times` 方法的類型是 `Nat`、`Foo`。從這些中,找到與"{1}"類型匹配的一個。
|
||||
有兩種類型的符合性確定。它們是篩式判斷和記錄式判斷。這是通過篩子類型確定來完成的。
|
||||
|
||||
##篩型確定
|
||||
|
||||
檢查候選類型是否與 `1` 的類型 `{1}` 兼容。與“{1}”兼容的篩子類型有“{0, 1}”、“0..9”等。
|
||||
檢查候選類型是否與 `1` 的類型 `{1}` 兼容。與"{1}"兼容的篩子類型有"{0, 1}"、"0..9"等。
|
||||
有限元代數類型,例如 `0..1 或 3..4`、`-1..2 和 0..3`,在聲明為基本類型(即 {0, 1, 3, 4}`,`{0, 1, 2}`)。
|
||||
在這種情況下,`Nat` 是 `0.._ == {I: Int | I >= 0}`,所以 `{1}` 與 `Nat` 兼容。
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
~~A:Erg的可執行系統EVM(Erg VirtualMachine)執行Erg字節碼,是Python字節碼的擴展。它在 Python 字節碼中引入了靜態類型系統和其他特性(例如向不帶參數的指令引入參數,以及在自由編號中實現唯一指令)。這讓 Erg 可以無縫調用 Python 代碼并快速執行。~~
|
||||
|
||||
A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Python 相同的解釋器上。最初,我們計劃開發一個兼容 Cpython 的解釋器,并將其與編譯器結合起來形成“Erg”。但是,由于處理系統的發展遠遠落后于編譯器,我們決定提前只發布編譯器(但解釋器仍在開發中)。
|
||||
A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Python 相同的解釋器上。最初,我們計劃開發一個兼容 Cpython 的解釋器,并將其與編譯器結合起來形成"Erg"。但是,由于處理系統的發展遠遠落后于編譯器,我們決定提前只發布編譯器(但解釋器仍在開發中)。
|
||||
|
||||
## 哪些語言影響了Erg?
|
||||
|
||||
|
@ -22,15 +22,15 @@ A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Pyth
|
|||
答:Erg 設計的動機之一是擁有一種易于使用且具有強大類型系統的語言。即具有類型推斷、Kind、依賴類型等的語言。
|
||||
Julia 是可以有類型的,但它確實是一種動態類型語言,不具備靜態類型語言的編譯時錯誤檢測優勢。
|
||||
|
||||
## Erg 支持多種編程風格,包括函數式和面向對象的編程。這不是與 Python 的“應該有一種——最好只有一種——明顯的方法”相反嗎?
|
||||
## Erg 支持多種編程風格,包括函數式和面向對象的編程。這不是與 Python 的"應該有一種——最好只有一種——明顯的方法"相反嗎?
|
||||
|
||||
答:在 Erg 中,該術語是在更狹窄的上下文中使用的。例如,Erg API 中一般沒有別名;在這種情況下,Erg是“唯一一種方式”。
|
||||
答:在 Erg 中,該術語是在更狹窄的上下文中使用的。例如,Erg API 中一般沒有別名;在這種情況下,Erg是"唯一一種方式"。
|
||||
在更大的上下文中,例如 FP 或 OOP,只有一種做事方式并不一定很方便。
|
||||
例如,JavaScript 有幾個庫可以幫助創建不可變的程序,而 C 有幾個用于垃圾收集的庫。
|
||||
然而,即使是這樣的基本功能也有多個庫不僅需要時間來選擇,而且在集成使用不同庫的代碼時也會產生很大的困難。
|
||||
即使在純函數式語言 Haskell 中,也有支持 OOP 的庫。
|
||||
如果程序員沒有一些東西,他們會自己創造它們。因此,我們認為將它們作為標準提供會更好。
|
||||
這也符合 Python 的“含電池”概念。
|
||||
這也符合 Python 的"含電池"概念。
|
||||
|
||||
## Erg 這個名字的由來是什么?
|
||||
|
||||
|
|
|
@ -4,16 +4,17 @@
|
|||
|
||||
## Erg內存管理模型
|
||||
|
||||
在CPython後端中使用所有權 + Python內存管理模型(不過Erg代碼中的循環引用不會通過GC處理[詳見](syntax/18_ownership.md/#循環引用))
|
||||
在CPython後端中使用所有權 + Python內存管理模型(不過Erg代碼中的循環引用不會通過GC處理詳見[此處](syntax/18_ownership.md/#循環引用))
|
||||
|
||||
在Erg自己的虛擬機(Dyne)中使用所有權 + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf)內存管理模型,如果Erg代碼使用了Python API那麼這些Erg代碼使用跟踪垃圾回收內存管理模型
|
||||
|
||||
在LLVM, WASM後端使用所有權 + [Perceus](https://www.microsoft.com/en-us/research/uploads/prod/2020/11/perceus-tr-v1.pdf)內存管理模型
|
||||
|
||||
__注意__: Erg 引入所有權系統的動機不是像 Rust 那樣“不依賴 GC 的內存管理”。
|
||||
首先,Erg 目前唯一可用前端編譯Erg為Python字節碼,因此使用了 GC。
|
||||
Erg 所有權系統的目標是“可變狀態的本地化”。 Erg 有一個附屬於可變對象的所有權概念。
|
||||
這是因為共享可變狀態容易出現錯誤,甚至違反類型安全(參見 [此處](../syntax/type/advanced/shared.md#共享参考))。這是一個判斷決定。
|
||||
無論是什麼後端都不需要因為內存管理的不同對代碼進行任何更改
|
||||
|
||||
__注意__: Erg 引入所有權系統的動機不是像 Rust 那樣"不依賴 GC 的內存管理"。
|
||||
Erg 所有權系統的目標是"可變狀態的本地化"。 Erg 有一個附屬於可變對象的所有權概念。
|
||||
這是因為共享可變狀態容易出現錯誤,甚至違反類型安全(參見 [此處](../syntax/type/advanced/shared.md#共享參考))。這是一個判斷決定。
|
||||
|
||||
## 為什麼類型參數要大括號 || 而不是 <> 或 []?
|
||||
|
||||
|
@ -75,7 +76,7 @@ try!:
|
|||
exit 1
|
||||
```
|
||||
|
||||
在引入 Python 函數時,缺省情況下,所有函數都被視為包含異常,返回類型為。如果你知道不調度異常,請在<gtr=“12”/>中指明。
|
||||
在引入 Python 函數時,缺省情況下,所有函數都被視為包含異常,返回類型為。如果你知道不調度異常,請在<gtr="12"/>中指明。
|
||||
|
||||
此外,Erg 沒有引入異常機制的另一個原因是它計劃引入並行編程的功能。這是因為異常機制與並行執行不兼容(例如,如果並行執行導致多個異常,則很難處理)。
|
||||
|
||||
|
@ -111,6 +112,6 @@ A:沒有那個計劃。最重要的原因是,如果允許定義自己的運
|
|||
|
||||
但是,確實也不是沒有方法可以不在語言上特殊對待副作用。例如,可以用代數效果(類型系統上的功能)替代過程。但這樣的合一併不總是正確的。例如,Haskell 沒有對字符串進行特殊處理,只是一個字符數組,但這種抽像是錯誤的。
|
||||
|
||||
什麼情況下,可以說合一化是錯的?一個指標是“是否會因其合一而難以看到錯誤信息”。 Erg 設計師發現,將副作用特殊處理會使錯誤消息更容易閱讀。
|
||||
什麼情況下,可以說合一化是錯的?一個指標是"是否會因其合一而難以看到錯誤信息"。 Erg 設計師發現,將副作用特殊處理會使錯誤消息更容易閱讀。
|
||||
|
||||
Erg 有一個強大的類型系統,但並不是所有的類型都決定了它。如果這樣做了,你的下場就跟 Java 試圖用類來控制一切一樣。
|
||||
|
|
|
@ -14,15 +14,15 @@
|
|||
|
||||
答:不,沒有。所有對象都至少屬于 `Object` 類,但是這種類型只提供了一組最小的屬性,所以你不能像使用 Any 那樣對它做任何你想做的事情。
|
||||
`Object` 類通過`match` 等動態檢查轉換為所需的類型。它與Java 和其他語言中的`Object` 是同一種。
|
||||
在 Erg 世界中,沒有像 TypeScript 那樣的混亂和絕望,其中 API 定義是“Any”。
|
||||
在 Erg 世界中,沒有像 TypeScript 那樣的混亂和絕望,其中 API 定義是"Any"。
|
||||
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么區別?
|
||||
|
||||
A:`Never` 是一種“不可能”的類型。產生運行時錯誤的子例程將“Never”(或“Never”的合并類型)作為其返回類型。該程序將在檢測到這一點后立即停止。盡管 `Never` 類型在定義上也是所有類型的子類,但 `Never` 類型的對象永遠不會出現在 Erg 代碼中,也永遠不會被創建。 `{}` 等價于 `Never`。
|
||||
A:`Never` 是一種"不可能"的類型。產生運行時錯誤的子例程將"Never"(或"Never"的合并類型)作為其返回類型。該程序將在檢測到這一點后立即停止。盡管 `Never` 類型在定義上也是所有類型的子類,但 `Never` 類型的對象永遠不會出現在 Erg 代碼中,也永遠不會被創建。 `{}` 等價于 `Never`。
|
||||
`Ellipsis` 是一個表示省略號的對象,來自 Python。
|
||||
`NotImplemented` 也來自 Python。它被用作未實現的標記,但 Erg 更喜歡產生錯誤的 `todo` 函數。
|
||||
`None` 是 `NoneType` 的一個實例。它通常與 `Option` 類型一起使用。
|
||||
`()` 是一個單元類型和它自己的一個實例。當您想要返回“無意義的值”(例如過程的返回值)時使用它。
|
||||
`()` 是一個單元類型和它自己的一個實例。當您想要返回"無意義的值"(例如過程的返回值)時使用它。
|
||||
|
||||
## 為什么 `x = p!()` 有效但 `f() = p!()` 會導致 EffectError?
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ stack.push(consts[namei])
|
|||
```
|
||||
|
||||
在常量表中加載常量。
|
||||
目前(Python 3.9),在 CPython 中,每個 lambda 函數都是 MAKE_FUNCTION,名稱為“\<lambda\>”
|
||||
目前(Python 3.9),在 CPython 中,每個 lambda 函數都是 MAKE_FUNCTION,名稱為"\<lambda\>"
|
||||
|
||||
```console
|
||||
>>> dis.dis("[1,2,3].map(lambda x: x+1)")
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
## PyString 對象
|
||||
|
||||
* 如果我使用 ascii 以外的字符,它會變成 PyUnicode 嗎?
|
||||
* “あ”、“𠮷”和“α”是 PyUnicode(不再使用?)
|
||||
* "あ"、"𠮷"和"α"是 PyUnicode(不再使用?)
|
||||
|
||||
* 0 字節:0x73(表示`s`)
|
||||
* 1~4 字節:字符串長度
|
||||
|
|
|
@ -47,11 +47,11 @@
|
|||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module
|
||||
File "<stdin>", line 3, in g
|
||||
類型錯誤:只能將str(不是“int”)連接到str
|
||||
類型錯誤:只能將str(不是"int")連接到str
|
||||
```
|
||||
|
||||
Erg 靜態檢查與父類的一致性。
|
||||
重寫時必須給出“Override”裝飾器,并且重寫函數的類型必須是被重寫函數類型的子類型。
|
||||
重寫時必須給出"Override"裝飾器,并且重寫函數的類型必須是被重寫函數類型的子類型。
|
||||
|
||||
```python
|
||||
>>> C = Class()
|
||||
|
@ -61,7 +61,7 @@ Erg 靜態檢查與父類的一致性。
|
|||
>>> D = Inherit C
|
||||
... .f self = "a"
|
||||
...
|
||||
錯誤[#XX]:文件“<stdin>”,第 5 行,在 D 中
|
||||
錯誤[#XX]:文件"<stdin>",第 5 行,在 D 中
|
||||
要覆蓋 f,必須添加 `Override` 裝飾器,其類型必須是 `Self.() -> Nat` 或其子類型
|
||||
f(self) 已在 C 中定義。要覆蓋 f,必須添加 `Override` 裝飾器,其類型必須為 `Self. 要覆蓋,必須給它一個 `Override` 裝飾器,并且它的類型必須是 `Self.() -> Nat` 或 that.f(self) 的子類型。
|
||||
```
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
|
||||
## 你好,世界!
|
||||
|
||||
首先,讓我們做“Hello World”。
|
||||
首先,讓我們做"Hello World"。
|
||||
|
||||
```python
|
||||
print!("Hello, World!")
|
||||
|
@ -30,8 +30,8 @@ print!(f(x, y)) # OK
|
|||
print! f(x, y) # OK
|
||||
print! f(x, g y) # OK
|
||||
print! f x, y # NG, 可以理解為 `print!(f(x), y)` 或 `print!(f(x, y))` print!
|
||||
print!(f x, y) # NG, 可以表示“print!(f(x),y)”或“print!(f(x,y))”
|
||||
print! f(x, g y, z) # NG, 可以表示“print!(x,g(y),z)”或“print!(x,g(y,z))”
|
||||
print!(f x, y) # NG, 可以表示"print!(f(x),y)"或"print!(f(x,y))"
|
||||
print! f(x, g y, z) # NG, 可以表示"print!(x,g(y),z)"或"print!(x,g(y,z))"
|
||||
```
|
||||
|
||||
## 腳本
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
0.00, -0.0, 0.1, 400.104, ...
|
||||
```
|
||||
|
||||
如果“比率”文字的整數或小數部分為`0`,則可以省略`0`
|
||||
如果"比率"文字的整數或小數部分為`0`,則可以省略`0`
|
||||
|
||||
```python
|
||||
assert 1.0 == 1.
|
||||
|
@ -46,7 +46,7 @@ assert "\{1+1}\" == "\{{s}\}"
|
|||
|
||||
### 指數字面量
|
||||
|
||||
這是學術計算中常用的表示指數符號的文字。 它是“比率”類型的一個實例。
|
||||
這是學術計算中常用的表示指數符號的文字。 它是"比率"類型的一個實例。
|
||||
該符號與 Python 中的符號相同。
|
||||
|
||||
```python
|
||||
|
@ -135,7 +135,7 @@ assert 0.0f32 == 0.0f64
|
|||
1+2im, 0.4-1.2im, 0im, im
|
||||
```
|
||||
|
||||
一個“復雜”對象只是一個虛數單位對象`im`的算術組合
|
||||
一個"復雜"對象只是一個虛數單位對象`im`的算術組合
|
||||
|
||||
## *-less 乘法
|
||||
|
||||
|
|
|
@ -11,10 +11,10 @@
|
|||
n = 1
|
||||
```
|
||||
|
||||
以這種方式定義的“n”此后可以用作表示整數對象“1”的變量。 該系統稱為分配(或綁定)。
|
||||
以這種方式定義的"n"此后可以用作表示整數對象"1"的變量。 該系統稱為分配(或綁定)。
|
||||
我們剛剛說過`1`是一個對象。 稍后我們將討論對象是什么,但現在我們假設它是可以賦值的,即在賦值運算符的右側(`=` 等)。
|
||||
|
||||
如果要指定變量的“類型”,請執行以下操作。 類型大致是一個對象所屬的集合,后面會解釋。
|
||||
如果要指定變量的"類型",請執行以下操作。 類型大致是一個對象所屬的集合,后面會解釋。
|
||||
這里我們指定`n`是自然數(`Nat`)類型。
|
||||
|
||||
```python
|
||||
|
@ -39,7 +39,7 @@ i = i + 1 # 分配錯誤:不能分配兩次
|
|||
```
|
||||
|
||||
您可以在內部范圍內定義具有相同名稱的變量,但您只是覆蓋它,而不是破壞性地重寫它的值。 如果您返回外部范圍,該值也會返回。
|
||||
請注意,這是與 Python “語句”范圍不同的行為。
|
||||
請注意,這是與 Python "語句"范圍不同的行為。
|
||||
這種功能通常稱為陰影。 但是,與其他語言中的陰影不同,您不能在同一范圍內進行陰影。
|
||||
|
||||
```python
|
||||
|
@ -119,7 +119,7 @@ Del y, Z
|
|||
f(2) # 名稱錯誤:f 未定義(在第 6 行中刪除)
|
||||
```
|
||||
|
||||
注意 `Del` 只能刪除用戶自定義模塊中定義的變量。 無法刪除諸如“True”之類的內置常量。
|
||||
注意 `Del` 只能刪除用戶自定義模塊中定義的變量。 無法刪除諸如"True"之類的內置常量。
|
||||
|
||||
```python
|
||||
Del True # 類型錯誤:無法刪除內置常量
|
||||
|
@ -149,7 +149,7 @@ C == D # 類型錯誤:無法比較類對象
|
|||
```
|
||||
|
||||
嚴格來說,`=` 不會將右側的值直接分配給左側的標識符。
|
||||
在函數和類對象的情況下,執行“修改”,例如將變量名稱信息賦予對象。 但是,結構類型并非如此。
|
||||
在函數和類對象的情況下,執行"修改",例如將變量名稱信息賦予對象。 但是,結構類型并非如此。
|
||||
|
||||
```python
|
||||
f x = x
|
||||
|
|
|
@ -17,7 +17,7 @@ i: {2}
|
|||
```
|
||||
|
||||
賦值后的聲明類似于`assert`的類型檢查,但具有在編譯時檢查的特點。
|
||||
在運行時通過`assert`進行類型檢查可以檢查“可能是Foo類型”,但是在編譯時通過`:`進行類型檢查是嚴格的:如果類型未確定為“類型Foo”,則不會通過 檢查會出現錯誤。
|
||||
在運行時通過`assert`進行類型檢查可以檢查"可能是Foo類型",但是在編譯時通過`:`進行類型檢查是嚴格的:如果類型未確定為"類型Foo",則不會通過 檢查會出現錯誤。
|
||||
|
||||
```python
|
||||
i = (-1..10).sample!
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/04_function.md&commit_hash=51de3c9d5a9074241f55c043b9951b384836b258)
|
||||
|
||||
函數是一個塊,它接受一個“參數”,對其進行處理,并將其作為“返回值”返回。 定義如下。
|
||||
函數是一個塊,它接受一個"參數",對其進行處理,并將其作為"返回值"返回。 定義如下。
|
||||
|
||||
```python
|
||||
add x, y = x + y
|
||||
|
@ -126,7 +126,7 @@ f x := 1, y := x = ... # NG
|
|||
輸出其參數的日志(記錄)的 `log` 函數可以采用任意數量的參數。
|
||||
|
||||
```python
|
||||
記錄“你好”、“世界”、“!” # 你好世界 !
|
||||
記錄"你好"、"世界"、"!" # 你好世界 !
|
||||
```
|
||||
|
||||
要定義這樣的函數,請將 `...` 添加到參數中。 這樣,函數將參數作為可變長度數組接收
|
||||
|
@ -158,7 +158,7 @@ fib 1 = 1
|
|||
fib(n: Nat): Nat = fib(n - 1) + fib(n - 2)
|
||||
```
|
||||
|
||||
注意一個函數定義有多個模式不是所謂的重載(multiple definition); 一個函數只有一個定義。 在上面的示例中,“n”必須與“0”或“1”屬于同一類型。 此外,與 `match` 一樣,模式匹配是從上到下完成的。
|
||||
注意一個函數定義有多個模式不是所謂的重載(multiple definition); 一個函數只有一個定義。 在上面的示例中,"n"必須與"0"或"1"屬于同一類型。 此外,與 `match` 一樣,模式匹配是從上到下完成的。
|
||||
|
||||
如果不同類的實例混合在一起,最后一個定義必須指定函數參數的類型為`Or`
|
||||
|
||||
|
@ -190,7 +190,7 @@ fib 1 = 1
|
|||
|
||||
遞歸函數是在其定義中包含自身的函數。
|
||||
|
||||
作為一個簡單的例子,讓我們定義一個執行階乘計算的函數`factorial`。 階乘是“將所有小于或等于的正數相乘”的計算。
|
||||
作為一個簡單的例子,讓我們定義一個執行階乘計算的函數`factorial`。 階乘是"將所有小于或等于的正數相乘"的計算。
|
||||
5 的階乘是 `5*4*3*2*1 == 120`。
|
||||
|
||||
```python
|
||||
|
@ -214,7 +214,7 @@ factorial 1 = 1
|
|||
factorial n = n * factorial(n - 1)
|
||||
```
|
||||
|
||||
但是,即使您可以推理,您也應該明確指定遞歸函數的類型。 在上面的例子中,像“factorial(-1)”這樣的代碼可以工作,但是
|
||||
但是,即使您可以推理,您也應該明確指定遞歸函數的類型。 在上面的例子中,像"factorial(-1)"這樣的代碼可以工作,但是
|
||||
|
||||
```python
|
||||
factorial(-1) == -1 * factorial(-2) == -1 * -2 * factorial(-3) == ...
|
||||
|
|
|
@ -13,7 +13,7 @@ result: Option Int = if! Bool.sample!(), do:
|
|||
print! result # None (or 1)
|
||||
```
|
||||
|
||||
`.sample!()` 返回一組隨機值。 如果返回值為真,`print! “真”`被執行。
|
||||
`.sample!()` 返回一組隨機值。 如果返回值為真,`print! "真"`被執行。
|
||||
如果條件為假,您還可以指定要執行的操作; 第二個 do 塊稱為 else 塊。
|
||||
|
||||
```python
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/syntax/07_side_effect.md&commit_hash=51de3c9d5a9074241f55c043b9951b384836b258)
|
||||
|
||||
我們一直忽略了解釋“!”的含義,但現在它的含義終于要揭曉了。 這個 `!` 表示這個對象是一個帶有“副作用”的“過程”。 過程是具有副作用的函數。
|
||||
我們一直忽略了解釋"!"的含義,但現在它的含義終于要揭曉了。 這個 `!` 表示這個對象是一個帶有"副作用"的"過程"。 過程是具有副作用的函數。
|
||||
|
||||
```python
|
||||
f x = print! x # EffectError: 不能為函數分配有副作用的對象
|
||||
|
@ -82,11 +82,11 @@ D = Class {i = Int}
|
|||
assert C == D # 類型錯誤:無法比較類
|
||||
```
|
||||
|
||||
言歸正傳:Erg 中“副作用”的準確定義是
|
||||
言歸正傳:Erg 中"副作用"的準確定義是
|
||||
|
||||
* 訪問可變的外部信息。
|
||||
|
||||
“外部”一般是指外部范圍; Erg 無法觸及的計算機資源和執行前/執行后的信息不包含在“外部”中。 “訪問”包括閱讀和寫作。
|
||||
"外部"一般是指外部范圍; Erg 無法觸及的計算機資源和執行前/執行后的信息不包含在"外部"中。 "訪問"包括閱讀和寫作。
|
||||
|
||||
例如,考慮 `print!` 過程。 乍一看,`print!` 似乎沒有重寫任何變量。 但如果它是一個函數,它可以重寫外部變量,例如,使用如下代碼:
|
||||
|
||||
|
@ -103,7 +103,7 @@ image = cam.shot!()
|
|||
n = ocr.read_num(image) # n = 3.141592
|
||||
```
|
||||
|
||||
將“camera”模塊視為為特定相機產品提供 API 的外部庫,將“ocr”視為用于 OCR(光學字符識別)的庫。
|
||||
將"camera"模塊視為為特定相機產品提供 API 的外部庫,將"ocr"視為用于 OCR(光學字符識別)的庫。
|
||||
直接的副作用是由 `cam.shot!()` 引起的,但顯然這些信息是從 `f` 泄露的。 因此,`print!` 本質上不可能是一個函數。
|
||||
|
||||
然而,在某些情況下,您可能希望臨時檢查函數中的值,而不想為此目的在相關函數中添加 `!`。 在這種情況下,可以使用 `log` 函數。
|
||||
|
@ -116,7 +116,7 @@ print! "this will be printed immediately"
|
|||
# 這將在執行后打印
|
||||
```
|
||||
|
||||
如果沒有反饋給程序,或者換句話說,如果沒有外部對象可以使用內部信息,那么信息的“泄漏”是可以允許的。 只需要不“傳播”信息。
|
||||
如果沒有反饋給程序,或者換句話說,如果沒有外部對象可以使用內部信息,那么信息的"泄漏"是可以允許的。 只需要不"傳播"信息。
|
||||
|
||||
<p align='center'>
|
||||
<a href='./06_operator.md'>上一頁</a> | <a href='./08_procedure.md'>下一頁</a>
|
||||
|
|
|
@ -68,7 +68,7 @@ Unit 是所有元素 0 元組的父類。
|
|||
() > (Str; 0)
|
||||
```
|
||||
|
||||
該對象的用途是用于沒有參數和沒有返回值的過程等。Erg 子例程必須有參數和返回值。 但是,在某些情況下,例如過程,可能沒有有意義的參數或返回值,只有副作用。 在這種情況下,我們將單位用作“無意義的正式值”
|
||||
該對象的用途是用于沒有參數和沒有返回值的過程等。Erg 子例程必須有參數和返回值。 但是,在某些情況下,例如過程,可能沒有有意義的參數或返回值,只有副作用。 在這種情況下,我們將單位用作"無意義的正式值"
|
||||
|
||||
```python
|
||||
# ↓ Actually, this parenthesis is a unit
|
||||
|
@ -78,12 +78,12 @@ p!() =.
|
|||
p!: () => ()
|
||||
```
|
||||
|
||||
但是,在這種情況下,Python 傾向于使用“無”而不是單位。
|
||||
但是,在這種情況下,Python 傾向于使用"無"而不是單位。
|
||||
在 Erg 中,當您從一開始就確定操作不會返回有意義的值(例如在過程中)時,您應該使用 `()`,并且當操作可能失敗并且您可能會返回 `None` 將一無所獲,例如在檢索元素時。
|
||||
|
||||
## 參數和元組
|
||||
|
||||
實際上,Erg 的所有 `Callable` 對象都是一個參數和一個返回值; 一個接受 N 個參數的子例程只是接收“一個具有 N 個元素的元組”作為參數。
|
||||
實際上,Erg 的所有 `Callable` 對象都是一個參數和一個返回值; 一個接受 N 個參數的子例程只是接收"一個具有 N 個元素的元組"作為參數。
|
||||
|
||||
```python
|
||||
# f x = ... 被隱式假設為 f(x) = ... 被認為是
|
||||
|
@ -101,7 +101,7 @@ assert f in T: {(T,) -> T | T}
|
|||
assert g in {(Int, ... (Int; N)) -> (Int; N) | N: Nat}
|
||||
```
|
||||
|
||||
準確地說,函數的輸入不是元組,而是“具有默認屬性的命名元組”。 這是一個特殊的元組,只能在函數參數中使用,可以像記錄一樣命名,并且可以有默認值。
|
||||
準確地說,函數的輸入不是元組,而是"具有默認屬性的命名元組"。 這是一個特殊的元組,只能在函數參數中使用,可以像記錄一樣命名,并且可以有默認值。
|
||||
|
||||
```python
|
||||
f(x: Int, y=0) = x + y
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue