mirror of
https://github.com/erg-lang/erg.git
synced 2025-09-30 12:51:10 +00:00
trifle
This commit is contained in:
parent
ad3fac86ac
commit
37abfb36d3
58 changed files with 244 additions and 386 deletions
|
@ -22,7 +22,7 @@ Erg のバグだと思われる動作を見つけた場合は、[報告](https:/
|
|||
|
||||
私たちは常に、ドキュメントをさまざまな言語バージョンに翻訳してくれる人を探しています。
|
||||
|
||||
ドキュメントが他の言語に比べて古くなっていることに気づき、内容を更新したいという方も歓迎します ([こちら](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362) を参照)。これを行う方法について)。
|
||||
ドキュメントが他の言語に比べて古くなっていることに気づき、内容を更新したいという方も歓迎します ([こちら](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362) を参照)。これを行う方法について)。
|
||||
|
||||
## 質問する
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
我们一直在寻找将我们的文件翻译成各种语言版本的人。
|
||||
|
||||
我们也欢迎那些发现文档与其他语言相比已经过时并希望更新内容的人(请参阅[此处](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362)如何做到这一点)。
|
||||
我们也欢迎那些发现文档与其他语言相比已经过时并希望更新内容的人(请参阅[此处](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362)如何做到这一点)。
|
||||
|
||||
## 提问
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
请求总是受欢迎的,但请记住,它们不会总是被接受。许多问题都有取舍。
|
||||
|
||||
不要拦截其他人已分配的问题(检查 GitHub 上的受理人)。如果认为一个人处理起来太困难,我们会呼吁更多的支持。
|
||||
不要拦截其他人已分配的问题(检查 GitHub 上的受理人)。如果认为一个人处理起来太困难,我们会呼吁更多的支持。
|
||||
|
||||
在提出新功能之前,请考虑通过组合现有功能是否可以轻松解决该功能。
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
我們一直在尋找將我們的文件翻譯成各種語言版本的人。
|
||||
|
||||
我們也歡迎那些發現文檔與其他語言相比已經過時並希望更新內容的人(請參閱[此處](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362)如何做到這一點)。
|
||||
我們也歡迎那些發現文檔與其他語言相比已經過時並希望更新內容的人(請參閱[此處](https://github.com/erg-lang/erg/issues/48#issuecomment-1218247362)如何做到這一點)。
|
||||
|
||||
## 提問
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
|||
|
||||
請求總是受歡迎的,但請記住,它們不會總是被接受。許多問題都有取捨。
|
||||
|
||||
不要攔截其他人已分配的問題(檢查 GitHub 上的受理人)。如果認為一個人處理起來太困難,我們會呼籲更多的支持。
|
||||
不要攔截其他人已分配的問題(檢查 GitHub 上的受理人)。如果認為一個人處理起來太困難,我們會呼籲更多的支持。
|
||||
|
||||
在提出新功能之前,請考慮通過組合現有功能是否可以輕鬆解決該功能。
|
||||
|
||||
|
|
|
@ -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/compiler/trait_method_resolving.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
`Nat`は0以上の`Int`、つまり`Int`のサブタイプである。
|
||||
本来`Nat`はPythonのクラス階層には存在しない。Ergはこのパッチのメソッドをどうやって解決するのだろうか?
|
||||
本来`Nat`はPythonのクラス階層には存在しない。Ergはこのパッチのメソッドをどうやって解決するのだろうか?
|
||||
|
||||
```python
|
||||
1.times do:
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# ErgコードはPythonコードにどのようにトランスパイルされるか?
|
||||
# ErgコードはPythonコードにどのようにトランスパイルされるか?
|
||||
|
||||
[](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/transpile.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
|
|
|
@ -46,10 +46,10 @@ switch_lang!(
|
|||
|
||||
## FAQ
|
||||
|
||||
Q: `{RED}{foo}{RESET}` のような指定は何を意味するのでしょうか?
|
||||
Q: `{RED}{foo}{RESET}` のような指定は何を意味するのでしょうか?
|
||||
A: {RED}以降が赤色で表示されます。{RESET}で色を元に戻します。
|
||||
|
||||
Q: 自分の言語を追加したい場合、`"simplified_chinese" =>`の部分はどのように置き換えればよいですか?
|
||||
Q: 自分の言語を追加したい場合、`"simplified_chinese" =>`の部分はどのように置き換えればよいですか?
|
||||
A: 現在、以下の言語がサポートされています。
|
||||
|
||||
* "english" (デフォルト)
|
||||
|
|
|
@ -6,23 +6,23 @@
|
|||
個別の(よくある)技術的な問題については[こちら](./faq_technical.md)を、文法の決定経緯(なぜこのような文法になったのか)などについては
|
||||
[こちら](./dev_guide/why.md)を参照してください。
|
||||
|
||||
## ErgはPython互換言語というのはどういう意味なのですか?
|
||||
## ErgはPython互換言語というのはどういう意味なのですか?
|
||||
|
||||
~~A: Ergの実行系であるEVM(Erg VirtualMachine)はPythonバイトコードを拡張したErgバイトコードを実行します。これは静的型付けシステムなどをPythonバイトコードに導入したものです(引数を取らない命令に引数を導入したり、空き番号に独自命令を実装しています)。これにより、ErgはPythonのコードをシームレスに呼び出し、かつ高速な実行を実現しています。~~
|
||||
|
||||
A: ErgスクリプトはPythonのバイトコードにトランスパイルされます。つまり、Pythonと同じインタープリタ上で動作します。もともとはPythonインタープリタ(CPython)を拡張した上位互換処理系を開発し、コンパイラと合わせて「Erg」とする予定でしたが、処理系の開発がコンパイラに対して大きく遅れたため、コンパイラのみ先行公開する運びとしました。現在処理系は鋭意開発中です。
|
||||
|
||||
## Ergはどの言語から影響を受けましたか?
|
||||
## Ergはどの言語から影響を受けましたか?
|
||||
|
||||
両手でも数え切れないほどの言語から影響を受けていますが、中でも特に強く影響を受けているのはPython/Rust/Nim/Haskellです。
|
||||
Pythonからはオフサイドルールと互換言語として多くの意味論、Rustからは式指向とトレイト、Nimからはプロシージャ、Haskellからは関数型プログラミング関連の機能を受け継いでいます。
|
||||
|
||||
## Pythonを呼び出せる言語はJuliaなどがあります。なぜErgを作ったのですか?
|
||||
## Pythonを呼び出せる言語はJuliaなどがあります。なぜErgを作ったのですか?
|
||||
|
||||
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つのやり方しかないというのは必ずしも利便性をもたらすとは限りません。
|
||||
|
@ -32,7 +32,7 @@ A: Ergでは、その言葉はもう少し狭い意味で捉えられます。
|
|||
プログラマは、なければ自前で作ってしまうものなのです。それならば、標準で提供してしまったほうがよいと考えます。
|
||||
これは、Pythonの"Battery included"にも適合します。
|
||||
|
||||
## Ergの名前の由来はなんですか?
|
||||
## Ergの名前の由来はなんですか?
|
||||
|
||||
cgs単位系のエネルギーの単位ergから名前をつけられています。プログラマーにエネルギーを与える人間工学的(ergonomic)な言語というダブルミーニングです(後付けですが)。
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ id|T: Type| t: T = t
|
|||
y = id|Int| # OK
|
||||
```
|
||||
|
||||
## {i = 1}の型は{i = Int}ですが、OCamlなどでは{i: Int}となっています。なぜErgは前者の構文を採用したのですか?
|
||||
## {i = 1}の型は{i = Int}ですが、OCamlなどでは{i: Int}となっています。なぜErgは前者の構文を採用したのですか?
|
||||
|
||||
Ergは型自体も値として扱える設計になっているためです。
|
||||
|
||||
|
@ -49,13 +49,13 @@ S = {.i = Int}
|
|||
assert S.i == Int
|
||||
```
|
||||
|
||||
## Ergにマクロが実装される予定はありますか?
|
||||
## Ergにマクロが実装される予定はありますか?
|
||||
|
||||
現在のところありません。マクロには大きく分けて4つの目的があります。1つ目は、コンパイル時計算です。これは、Ergではコンパイル時関数がその役割を担っています。
|
||||
2つ目は、コード実行の遅延です。これはdoブロックで代用できます。3つ目は処理の共通化ですが、これについては多相関数と全称型がマクロよりもよい解決策です。4つ目は自動コード生成ですが、これは可読性の低下をもたらすためErgではあえて実現出来ないようにしています。
|
||||
このようにマクロの持つ機能の大部分はErgの型システムが肩代わりしているため、導入のモチベーションがないのです。
|
||||
|
||||
## なぜErgには例外機構がないのですか?
|
||||
## なぜErgには例外機構がないのですか?
|
||||
|
||||
多くの場合において、`Result`型によるエラーハンドリングがより良い解決策であるからです。`Result`型は比較的新しいプログラミング言語では採用されている事例の多いエラーハンドリング手法です。
|
||||
|
||||
|
@ -83,12 +83,12 @@ Pythonの関数を導入する場合は、デフォルトではすべて例外
|
|||
また、Ergが例外機構を導入していない理由として、並列プログラミングのための機能導入を予定しているからというのもあります。
|
||||
というのも、例外機構は並列実行と相性が悪い(並列実行により複数の例外が発生した場合などの対処が面倒など)のです。
|
||||
|
||||
## ErgはバッドプラクティスとされているPythonの機能を排除しているように見受けられますが、なぜ継承は廃止しなかったのですか?
|
||||
## ErgはバッドプラクティスとされているPythonの機能を排除しているように見受けられますが、なぜ継承は廃止しなかったのですか?
|
||||
|
||||
Pythonのライブラリには継承されることを前提に設計されているクラスがあり、継承を完全に廃止してしまうとこれらの運用に問題が生じるためです。
|
||||
とはいえ、Ergではデフォルトでクラスがfinalであり多重・多層継承も原則禁止されているので、継承は比較的安全に使用できます。
|
||||
|
||||
## なぜ多相関数のサブタイプ推論はデフォルトで記名的トレイトを指すのですか?
|
||||
## なぜ多相関数のサブタイプ推論はデフォルトで記名的トレイトを指すのですか?
|
||||
|
||||
デフォルトで構造的トレイトを指すと、型指定が複雑になり、プログラマの意図しない挙動を混入させる恐れがあるためです。
|
||||
|
||||
|
@ -101,16 +101,16 @@ f|T| x, y: T = x + y - x
|
|||
g|T| x, y: T = x + y - x
|
||||
```
|
||||
|
||||
## Ergには独自演算子を定義する機能は実装されませんか?
|
||||
## Ergには独自演算子を定義する機能は実装されませんか?
|
||||
|
||||
A: その予定はありません。一番の理由は、独自演算子の定義を許可すると、その結合順位をどうするかという問題が立ち上がるからです。独自演算子の定義が可能なScalaやHaskellなどではそれぞれ違った対応をしていますが、これは解釈の違いを生みかねない文法である証拠とみることができます。また独自演算子には可読性の低いコードが作られかねないというデメリットもあります。
|
||||
|
||||
## なぜErgでは+=のような拡張代入演算子を廃止してしまったのですか?
|
||||
## なぜErgでは+=のような拡張代入演算子を廃止してしまったのですか?
|
||||
|
||||
まず、Ergでは変数の可変性がありません。つまり、再代入ができません。一旦ある変数に紐付けられたオブジェクトは、スコープを外れて解放されるまでずっとその変数に束縛されます。Ergで可変性とはオブジェクトの可変性を意味します。これが分かれば、話は簡単です。例えば`i += 1`は`i = i + 1`を意味しますが、変数は再代入不可なので、このような構文は不正です。もう一つ、Ergの設計原則として演算子は副作用を持たないというものがあります。Pythonも概ねそうなっていますが、Dictなど一部のオブジェクトでは拡張代入演算子がオブジェクトの内部状態を変更します。これはあまり美しい設計とは言えません。
|
||||
そういうわけで拡張代入演算子はまるごと廃止されています。
|
||||
|
||||
## Ergはなぜ副作用のあるオブジェクトを文法的に特別扱いしているのですか?
|
||||
## Ergはなぜ副作用のあるオブジェクトを文法的に特別扱いしているのですか?
|
||||
|
||||
副作用の局所化は、コードのメンテナビリティにおいて重要な要素です。
|
||||
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
|
||||
根本的な文法の決定経緯については[こちら](./dev_guide/faq_syntax.md)を、なぜこの言語を作ったのか、この機能はどのように実装されているのかなど、より大きな話題は[こちら](./dev_guide/../faq_general.md)を参照してください。
|
||||
|
||||
## Ergに例外機構はないのですか?
|
||||
## Ergに例外機構はないのですか?
|
||||
|
||||
A: ありません。Ergでは代わりに`Result`型を使います。なぜErgに例外機構がないのかは[こちら](./dev_guide/faq_syntax.md#なぜergには例外機構がないのですか)を参照してください。
|
||||
|
||||
## ErgにはTypeScriptのAnyに相当する型はないのですか?
|
||||
## ErgにはTypeScriptのAnyに相当する型はないのですか?
|
||||
|
||||
A: ありません。すべてのオブジェクトは少なくとも`Object`クラスに属しますが、この型は最小限の属性を提供するのみの型で、Anyのように好き放題はできません。
|
||||
`Object`クラスは`match`などによる動的検査を通し目的の型に変換して使用します。Javaなどの`Object`と同じ類です。
|
||||
Ergの世界では、TypeScriptのようにAPIの定義を辿ったらAnyだったという絶望・混沌は生まれないのです。
|
||||
|
||||
## Never, {}, None, (), NotImplemented, Ellipsisは何が違うのですか?
|
||||
## Never, {}, None, (), NotImplemented, Ellipsisは何が違うのですか?
|
||||
|
||||
A: `Never`は「起こりえない」型です。実行時エラーを出すサブルーチンが、`Never`(または`Never`の合併型)を戻り値型とします。これを検知するとプログラムはすぐさま停止します。`Never`型は定義上すべての型のサブクラスでもありますが、`Never`型オブジェクトは決してErgコード上に出現しませんし、生成もされません。`{}`は`Never`と等価です。
|
||||
`Ellipsis`は省略を表すオブジェクトで、Python由来です。
|
||||
|
@ -24,12 +24,12 @@ A: `Never`は「起こりえない」型です。実行時エラーを出すサ
|
|||
`None`は`NoneType`のインスタンスです。`Option`型でよく使われます。
|
||||
`()`はユニット型であり、そのインスタンス自身でもあります。これはプロシージャの戻り値など「意味のない値」を返したいとき使われます。
|
||||
|
||||
## なぜ`x = p!()`は有効なのに`f() = p!()`はEffectErrorとなるのですか?
|
||||
## なぜ`x = p!()`は有効なのに`f() = p!()`はEffectErrorとなるのですか?
|
||||
|
||||
A: `!`は副作用の産物につけるマーカーではなく、副作用を起こしうるオブジェクトに付けるマーカーだからです。
|
||||
プロシージャ`p!`や可変型`T!`は副作用を起こす可能性がありますが、例えば`p!()`の戻り値が`Int`型だった場合、それ自体はもう副作用を起こしません。
|
||||
|
||||
## PythonのAPIを使用しようとしたとき、Pythonでは有効だったコードがErgでは型エラーになりました。これはどういうことですか?
|
||||
## PythonのAPIを使用しようとしたとき、Pythonでは有効だったコードがErgでは型エラーになりました。これはどういうことですか?
|
||||
|
||||
A: ErgのAPIはなるべくPythonのAPIの仕様に忠実に型付けられていますが、どうしても表現しきれないケースもあります。
|
||||
また、仕様上有効でも望ましくないと判断した入力(例えば、intを入力すべきところでfloatを入力してもよい仕様など)は、Erg開発チームの判断により型エラーとする可能性があります。
|
||||
|
|
|
@ -56,7 +56,7 @@ stack.push(consts[namei])
|
|||
fastlocals[namei] = stack.pop()
|
||||
おそらくトップレベルにおけるSTORE_NAMEに対応する
|
||||
参照のない(もしくは単一)変数がこれによって格納されると思われる
|
||||
わざわざグローバル空間が独自の命令を持っているのは最適化のため?
|
||||
わざわざグローバル空間が独自の命令を持っているのは最適化のため?
|
||||
|
||||
## LOAD_FAST(namei)
|
||||
|
||||
|
|
|
@ -37,8 +37,8 @@
|
|||
|
||||
## PyStringObject
|
||||
|
||||
* ascii以外の文字を使うとPyUnicodeになる?
|
||||
* "あ", "𠮷", "α"だとPyUnicodeになった(もう使われていない?)
|
||||
* ascii以外の文字を使うとPyUnicodeになる?
|
||||
* "あ", "𠮷", "α"だとPyUnicodeになった(もう使われていない?)
|
||||
|
||||
* 0 byte: 0x73 (means 's')
|
||||
* 1~4 byte: length of string
|
||||
|
@ -53,7 +53,7 @@
|
|||
## PyShortAsciiObject
|
||||
|
||||
* shortと言っているが、100文字以上あってもこれになる
|
||||
* というかshortじゃないasciiはない(shortはデータ型?)
|
||||
* というかshortじゃないasciiはない(shortはデータ型?)
|
||||
|
||||
* 0 byte: 0xFA (means 'z')
|
||||
* 1~4 byte: length of string
|
||||
|
|
|
@ -35,7 +35,7 @@ assert MonthsClass.new(12) in Months
|
|||
assert MonthsClass.new(2).name() == "february"
|
||||
```
|
||||
|
||||
## 結局、NSTとSSTどちらを使えばいいのか?
|
||||
## 結局、NSTとSSTどちらを使えばいいのか?
|
||||
|
||||
どちらにすればよいか判断がつかないときはNSTを推奨します。
|
||||
SSTはどんなユースケースでも破綻しないコードを書く抽象化能力が要求されます。よい抽象化を実現できれば高い生産性を発揮できますが、間違った抽象化(__見かけによる共通化__)を行うと逆効果となってしまいます。NSTは抽象性をあえて抑え、このリスクを減らすことができます。あなたがライブラリの実装者でないならば、NSTのみでコーディングを行っても悪くはないでしょう。
|
||||
|
|
|
@ -198,7 +198,7 @@ K(0).
|
|||
|
||||
## 全称型
|
||||
|
||||
前章で定義した`id`関数は任意の型になれる関数です。では、「`id`関数自体の型」は何なのでしょうか?
|
||||
前章で定義した`id`関数は任意の型になれる関数です。では、「`id`関数自体の型」は何なのでしょうか?
|
||||
|
||||
```python
|
||||
print! classof(id) # |T: Type| T -> T
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
> __Warning__: このドキュメントは情報が古く、全般に間違いを含みます。
|
||||
|
||||
Ergでは`id|T|(x: T): T = x`などのように色々な型を受け取れる関数、すなわち多相関数を定義できる。
|
||||
では、多相関数を受け取れる関数は定義できるだろうか?
|
||||
では、多相関数を受け取れる関数は定義できるだろうか?
|
||||
例えば、このような関数である(この定義は誤りを含むことに注意してほしい)。
|
||||
|
||||
```python
|
||||
|
|
|
@ -39,7 +39,7 @@ print! L # <kind L>
|
|||
```python
|
||||
i = j = 1 # SyntaxError: 不允许多次赋值
|
||||
print!(x=1) # SyntaxError: cannot use `=` in function arguments
|
||||
# 提示:您的意思是关键字参数(`x: 1`)吗?
|
||||
# 提示:您的意思是关键字参数(`x: 1`)吗?
|
||||
if True, do:
|
||||
i = 0 # SyntaxError: 块不能被赋值表达式终止
|
||||
```
|
||||
|
|
|
@ -3,11 +3,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/compiler/TODO_recov_suggest.md&commit_hash=d15cbbf7b33df0f78a575cff9679d84c36ea3ab1)
|
||||
|
||||
* `1 or 2`, `1 and 2` => `{1, 2}`?
|
||||
* `U = Inherit T` => 非类类型不能被继承,或者`U = Class T`?
|
||||
* `Int and Str` => 不允许多重继承,或者`Int or Str`?
|
||||
* `: [1, 2]` => `: {1, 2}`?
|
||||
* `: [Int, 2]` => `: [Int; 2]`?
|
||||
* `[Int; Str]` => `(Int, Str)`(Tuple) 还是 `[Int: Str]`(Dict)?
|
||||
* `{x: Int}` => `{x = Int}`?
|
||||
* `{x = Int}!` => `{x = Int!}`?
|
||||
* `U = Inherit T` => 非类类型不能被继承,或者`U = Class T`?
|
||||
* `Int and Str` => 不允许多重继承,或者`Int or Str`?
|
||||
* `: [1, 2]` => `: {1, 2}`?
|
||||
* `: [Int, 2]` => `: [Int; 2]`?
|
||||
* `[Int; Str]` => `(Int, Str)`(Tuple) 还是 `[Int: Str]`(Dict)?
|
||||
* `{x: Int}` => `{x = Int}`?
|
||||
* `{x = Int}!` => `{x = Int!}`?
|
||||
* `ref! immut_expr` => `ref! !immut_expr`?
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
* `t = {(record type)}` => `T = {(record type)}`?(只有定义为常量的类型才能用于类型说明)
|
||||
* `{I: Int | ...}!` => `{I: Int! | ...}`
|
||||
* for/while 块中的`return x`(`x != ()`) => `f::return`(外部块)?
|
||||
* for/while 块中的`return x`(`x != ()`) => `f::return`(外部块)?
|
|
@ -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/compiler/trait_method_resolving.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
`Nat` 是零个或多个`Int`,`Int` 的子类型。
|
||||
`Nat` 在 Python 类层次结构中不存在。 我想知道 Erg 是如何解决这个补丁方法的?
|
||||
`Nat` 在 Python 类层次结构中不存在。 我想知道 Erg 是如何解决这个补丁方法的?
|
||||
|
||||
```python
|
||||
1.times do:
|
||||
|
@ -19,7 +19,7 @@ Erg 在 `Int` 的 MRO 中有 `Int`、`Object`。它来自 Python(Python 中的`i
|
|||
|
||||
整数显然应该在其超类型中包含实数、复数甚至整数,但这一事实并没有出现在 Python 兼容层中。
|
||||
然而,`1 in Complex` 和 `1 in Num` 在 Erg 中实际上是 `True`。
|
||||
至于`Complex`,即使是与`Int`没有继承关系的类,也被判断为类型兼容。这到底是怎么回事?
|
||||
至于`Complex`,即使是与`Int`没有继承关系的类,也被判断为类型兼容。这到底是怎么回事?
|
||||
|
||||
~
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Erg 代码如何转译成 Python 代码?
|
||||
# Erg 代码如何转译成 Python 代码?
|
||||
|
||||
[](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/transpile.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ switch_lang!(
|
|||
|
||||
## FAQ
|
||||
|
||||
Q:像这样的指定是什么意思?A:{RED} 及更高版本将显示为红色。重新启动交互渲染。
|
||||
Q:像这样的指定是什么意思?A:{RED} 及更高版本将显示为红色。重新启动交互渲染。
|
||||
|
||||
Q:如果想添加自己的语言,该如何替换部分?答:目前支持以下语言。
|
||||
Q:如果想添加自己的语言,该如何替换部分?答:目前支持以下语言。
|
||||
|
||||
* "english"(默认设置)
|
||||
* "japanese" (日语)
|
||||
|
|
|
@ -3,26 +3,26 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228)
|
||||
|
||||
此常见问题解答适用于一般 Erg 初学者。
|
||||
对于个别(常见)技术问题,请参阅 [此处](./faq_technical.md) 了解个别(常见)技术问题,以及
|
||||
对于个别(常见)技术问题,请参阅 [此处](./faq_technical.md) 了解个别(常见)技术问题,以及
|
||||
[这里](./dev_guide/faq_syntax.md) 了解更多信息。
|
||||
|
||||
## Erg 是 Python 兼容语言是什么意思?
|
||||
## Erg 是 Python 兼容语言是什么意思?
|
||||
|
||||
~~A:Erg的可执行系统EVM(Erg VirtualMachine)执行Erg字节码,是Python字节码的扩展。它在 Python 字节码中引入了静态类型系统和其他特性(例如向不带参数的指令引入参数,以及在自由编号中实现唯一指令)。这让 Erg 可以无缝调用 Python 代码并快速执行。~~
|
||||
|
||||
A: Erg 代码被转译成 Python 字节码。也就是说,它运行在与 Python 相同的解释器上。最初,我们计划开发一个兼容 Cpython 的解释器,并将其与编译器结合起来形成“Erg”。但是,由于处理系统的发展远远落后于编译器,我们决定提前只发布编译器(但解释器仍在开发中)。
|
||||
|
||||
## 哪些语言影响了Erg?
|
||||
## 哪些语言影响了Erg?
|
||||
|
||||
我们受到的语言多于我们双手所能指望的数量,但 Python、Rust、Nim 和 Haskell 的影响最大。
|
||||
我们从 Python 继承了许多语义,从 Rust 继承了面向表达式和 trait,从 Nim 继承了过程,从 Haskell 继承了函数式编程相关的特性。
|
||||
|
||||
## 已经有一些语言可以调用Python,比如Julia。为什么要创建Erg?
|
||||
## 已经有一些语言可以调用Python,比如Julia。为什么要创建Erg?
|
||||
|
||||
答:Erg 设计的动机之一是拥有一种易于使用且具有强大类型系统的语言。即具有类型推断、Kind、依赖类型等的语言。
|
||||
Julia 是可以有类型的,但它确实是一种动态类型语言,不具备静态类型语言的编译时错误检测优势。
|
||||
|
||||
## Erg 支持多种编程风格,包括函数式和面向对象的编程。这不是与 Python 的“应该有一种——最好只有一种——明显的方法”相反吗?
|
||||
## Erg 支持多种编程风格,包括函数式和面向对象的编程。这不是与 Python 的“应该有一种——最好只有一种——明显的方法”相反吗?
|
||||
|
||||
答:在 Erg 中,该术语是在更狭窄的上下文中使用的。例如,Erg API 中一般没有别名;在这种情况下,Erg是“唯一一种方式”。
|
||||
在更大的上下文中,例如 FP 或 OOP,只有一种做事方式并不一定很方便。
|
||||
|
@ -32,7 +32,7 @@ Julia 是可以有类型的,但它确实是一种动态类型语言,不具
|
|||
如果程序员没有一些东西,他们会自己创造它们。因此,我们认为将它们作为标准提供会更好。
|
||||
这也符合 Python 的“含电池”概念。
|
||||
|
||||
## Erg 这个名字的由来是什么?
|
||||
## Erg 这个名字的由来是什么?
|
||||
|
||||
它以cgs单位系统中的能量单位erg命名。它具有双重含义:一种为程序员提供能量的符合人体工程学的语言。
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## 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代码使用跟踪垃圾回收内存管理模型
|
||||
|
||||
|
@ -13,28 +13,28 @@
|
|||
__注意__: Erg 引入所有权系统的动机不是像 Rust 那样“不依赖 GC 的内存管理”。
|
||||
首先,Erg 目前唯一可用前端编译Erg为Python字节码,因此使用了 GC。
|
||||
Erg 所有权系统的目标是“可变状态的本地化”。 Erg 有一个附属于可变对象的所有权概念。
|
||||
这是因为共享可变状态容易出现错误,甚至违反类型安全(参见 [此处](../syntax/type/advanced/shared.md#共享参考))。这是一个判断决定。
|
||||
这是因为共享可变状态容易出现错误,甚至违反类型安全(参见 [此处](../syntax/type/advanced/shared.md#共享参考))。这是一个判断决定。
|
||||
|
||||
## 为什么类型参数要大括号 || 而不是 <> 或 []?
|
||||
## 为什么类型参数要大括号 || 而不是 <> 或 []?
|
||||
|
||||
这是因为 `<>` 和 `[]` 会导致语法冲突。
|
||||
|
||||
```python
|
||||
# []版
|
||||
id[T: Type] [t]: [T] = t
|
||||
y = id[Int] # 这是一个功能吗?
|
||||
y = id[Int] # 这是一个功能吗?
|
||||
# <>版
|
||||
id<T: Type> {t: T} = t
|
||||
y = (id<Int, 1> 1) # 这是一个元组吗?
|
||||
y = (id<Int, 1> 1) # 这是一个元组吗?
|
||||
# {}版
|
||||
id{T: Type} {t: T} = t
|
||||
y = id{Int} # 这是一个功能吗?
|
||||
y = id{Int} # 这是一个功能吗?
|
||||
# ||版
|
||||
id|T: Type| t: T = t
|
||||
y = id|Int| # OK
|
||||
```
|
||||
|
||||
## {i=1} 的类型为 {i=Int},但在 OCaml 等环境中为 {i:Int}。为什么 Erg 采用前者的语法?
|
||||
## {i=1} 的类型为 {i=Int},但在 OCaml 等环境中为 {i:Int}。为什么 Erg 采用前者的语法?
|
||||
|
||||
Erg 设计为将类型本身也视为值。
|
||||
|
||||
|
@ -49,11 +49,11 @@ S = {.i = Int}
|
|||
assert S.i == Int
|
||||
```
|
||||
|
||||
## 你打算在 Erg 中实现宏吗?
|
||||
## 你打算在 Erg 中实现宏吗?
|
||||
|
||||
目前没有。宏观大致分为四个目的。第一个是编译时计算。这在 Erg 中由编译时函数负责。第二,代码执行的延迟。这可以用 do 块来代替。第三个是处理通用化,对此多相关数和全称类型是比宏观更好的解决方案。第四个是自动生成代码,但这会造成可读性的下降,所以我们不敢在 Erg 中实现。因此,宏的大部分功能都由 Erg 型系统承担,因此没有动力进行部署。
|
||||
|
||||
## 为什么 Erg 没有异常机制?
|
||||
## 为什么 Erg 没有异常机制?
|
||||
|
||||
因为在许多情况下,使用 `Result` 类型进行错误处理是更好的解决方案。 `Result` 类型是相对较新的编程语言中使用的常见错误处理技术。
|
||||
|
||||
|
@ -79,11 +79,11 @@ try!:
|
|||
|
||||
此外,Erg 没有引入异常机制的另一个原因是它计划引入并行编程的功能。这是因为异常机制与并行执行不兼容(例如,如果并行执行导致多个异常,则很难处理)。
|
||||
|
||||
## Erg 似乎消除了 Python 被认为是坏做法的功能,但为什么没有取消继承?
|
||||
## Erg 似乎消除了 Python 被认为是坏做法的功能,但为什么没有取消继承?
|
||||
|
||||
Python 的库中有一些类设计为继承,如果完全取消继承,这些操作就会出现问题。然而,由于 Erg 的类默认为 final,并且原则上禁止多重和多层继承,因此继承的使用相对安全。
|
||||
|
||||
## 为什么多相关数的子类型推理默认指向记名trait?
|
||||
## 为什么多相关数的子类型推理默认指向记名trait?
|
||||
|
||||
默认情况下,指向结构托盘会使类型指定变得复杂,并且可能会混合程序员的非预期行为。
|
||||
|
||||
|
@ -96,21 +96,21 @@ f|T| x, y: T = x + y - x
|
|||
g|T| x, y: T = x + y - x
|
||||
```
|
||||
|
||||
## Erg 是否实现了定义自己的运算符的功能?
|
||||
## Erg 是否实现了定义自己的运算符的功能?
|
||||
|
||||
A:没有那个计划。最重要的原因是,如果允许定义自己的运算符,就会出现如何处理组合顺序的问题。可以定义自己的运算符的 Scala 和 Haskell 等都有不同的对应,但这可以看作是可能产生解释差异的语法的证据。此外,独立运算符还有一个缺点,那就是可能产生可读性较低的代码。
|
||||
|
||||
## 为什么 Erg 取消了 += 这样的扩展赋值运算符?
|
||||
## 为什么 Erg 取消了 += 这样的扩展赋值运算符?
|
||||
|
||||
首先,Erg 中没有变量可变性。 换句话说,它不能被重新分配。 一旦一个对象绑定到一个变量,它就会一直绑定到该变量,直到它超出范围并被释放。 Erg 中的可变性意味着对象可变性。 一旦你知道了这一点,故事就很简单了。 例如,`i += 1` 表示 `i = i + 1`,但这样的语法是非法的,因为变量没有被重新分配。 Erg 的另一个设计原则是操作符不应该有副作用。 Python 大多是这样,但是对于某些对象,例如 Dict,扩展赋值运算符会改变对象的内部状态。 这不是一个非常漂亮的设计。
|
||||
这就是扩展赋值运算符完全过时的原因。
|
||||
|
||||
## 为什么 Erg 在语法上特别对待有副作用的过程?
|
||||
## 为什么 Erg 在语法上特别对待有副作用的过程?
|
||||
|
||||
副作用的局部化是代码维护的一个关键因素。
|
||||
|
||||
但是,确实也不是没有方法可以不在语言上特殊对待副作用。例如,可以用代数效果(类型系统上的功能)替代过程。但这样的合一并不总是正确的。例如,Haskell 没有对字符串进行特殊处理,只是一个字符数组,但这种抽象是错误的。
|
||||
|
||||
什么情况下,可以说合一化是错的?一个指标是“是否会因其合一而难以看到错误信息”。Erg 设计师发现,将副作用特殊处理会使错误消息更容易阅读。
|
||||
什么情况下,可以说合一化是错的?一个指标是“是否会因其合一而难以看到错误信息”。Erg 设计师发现,将副作用特殊处理会使错误消息更容易阅读。
|
||||
|
||||
Erg 有一个强大的类型系统,但并不是所有的类型都决定了它。如果这样做了,你的下场就跟 Java 试图用类来控制一切一样。
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
|
||||
有关如何确定语法的更多信息,请参阅 [此处](./dev_guide/faq_syntax.md) 了解基础语法决策,以及 [此处](./dev_guide/../faq_general.md)。
|
||||
|
||||
## Erg 中有异常机制吗?
|
||||
## Erg 中有异常机制吗?
|
||||
|
||||
答:不会。Erg 使用 `Result` 类型代替。请参阅 [此处](./dev_guide/faq_syntax.md) 了解 Erg 没有异常机制的原因。
|
||||
|
||||
## Erg 是否有与 TypeScript 的 `Any` 等价的类型?
|
||||
## Erg 是否有与 TypeScript 的 `Any` 等价的类型?
|
||||
|
||||
答:不,没有。所有对象都至少属于 `Object` 类,但是这种类型只提供了一组最小的属性,所以你不能像使用 Any 那样对它做任何你想做的事情。
|
||||
`Object` 类通过`match` 等动态检查转换为所需的类型。它与Java 和其他语言中的`Object` 是同一种。
|
||||
在 Erg 世界中,没有像 TypeScript 那样的混乱和绝望,其中 API 定义是“Any”。
|
||||
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么区别?
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么区别?
|
||||
|
||||
A:`Never` 是一种“不可能”的类型。产生运行时错误的子例程将“Never”(或“Never”的合并类型)作为其返回类型。该程序将在检测到这一点后立即停止。尽管 `Never` 类型在定义上也是所有类型的子类,但 `Never` 类型的对象永远不会出现在 Erg 代码中,也永远不会被创建。 `{}` 等价于 `Never`。
|
||||
`Ellipsis` 是一个表示省略号的对象,来自 Python。
|
||||
|
@ -24,12 +24,12 @@ A:`Never` 是一种“不可能”的类型。产生运行时错误的子例
|
|||
`None` 是 `NoneType` 的一个实例。它通常与 `Option` 类型一起使用。
|
||||
`()` 是一个单元类型和它自己的一个实例。当您想要返回“无意义的值”(例如过程的返回值)时使用它。
|
||||
|
||||
## 为什么 `x = p!()` 有效但 `f() = p!()` 会导致 EffectError?
|
||||
## 为什么 `x = p!()` 有效但 `f() = p!()` 会导致 EffectError?
|
||||
|
||||
`!` 不是副作用产品的标记,而是可能导致副作用的对象。
|
||||
过程 `p!` 和可变类型 `T!` 会引起副作用,但如果 `p!()` 的返回值是 `Int` 类型,它本身就不再引起副作用。
|
||||
|
||||
## 当我尝试使用 Python API 时,对于在 Python 中有效的代码,我在 Erg 中收到类型错误。这是什么意思?
|
||||
## 当我尝试使用 Python API 时,对于在 Python 中有效的代码,我在 Erg 中收到类型错误。这是什么意思?
|
||||
|
||||
A:Erg API 的类型尽可能接近 Python API 规范,但有些情况无法完全表达。
|
||||
此外,根据规范有效但被认为不合需要的输入(例如,在应该输入 int 时输入浮点数)可能会被 Erg 开发团队酌情视为类型错误。
|
|
@ -26,7 +26,7 @@ Python并不清楚可变和不可变/堆和值对象之间的区别,因此您
|
|||
另外,如果你想让你自己的类不可变,你必须经历一个乏味的过程。
|
||||
|
||||
```python
|
||||
# 你能相信这段代码对过去的 Python 版本有效吗?
|
||||
# 你能相信这段代码对过去的 Python 版本有效吗?
|
||||
i = 256
|
||||
assert i is 256
|
||||
i = 257
|
||||
|
|
|
@ -56,14 +56,14 @@ stack.push(consts[namei])
|
|||
fastlocals[namei] = stack.pop()
|
||||
可能对应于顶层的 STORE_NAME
|
||||
假定未引用(或单个)变量由此存储
|
||||
全局空间有自己的指令是为了优化吗?
|
||||
全局空间有自己的指令是为了优化吗?
|
||||
|
||||
## LOAD_FAST(名称索引)
|
||||
|
||||
```python
|
||||
stack.push(fastlocals[namei])
|
||||
```
|
||||
fastlocals 是变量名吗?
|
||||
fastlocals 是变量名吗?
|
||||
|
||||
## LOAD_CLOSURE(名称索引)
|
||||
|
||||
|
|
|
@ -1,145 +1,74 @@
|
|||
# Python bytecode specification
|
||||
# Python 字节码规范
|
||||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/python/bytecode_specification.md&commit_hash=9f6a4a43fcf7e4f58cabe6e5a7546820fd9f5ff4)
|
||||
|
||||
## Format
|
||||
|
||||
* 0~3 byte(u32): magic number (see common/bytecode.rs for details)
|
||||
* 4~7 byte(u32): 0 padding
|
||||
* 8~12 byte(u32): timestamp
|
||||
* 13~ byte(PyCodeObject): code object
|
||||
|
||||
## PyCodeObject
|
||||
|
||||
* 0 byte(u8): '0xe3' (prefix, this means code's 'c')
|
||||
* 01~04 byte(u32): number of args (co_argcount)
|
||||
* 05~08 byte(u32): number of position-only args (co_posonlyargcount)
|
||||
* 09~12 byte(u32): number of keyword-only args (co_kwonlyargcount)
|
||||
* 13~16 byte(u32): number of locals (co_nlocals)
|
||||
* 17~20 byte(u32): stack size (co_stacksize)
|
||||
* 21~24 byte(u32): flags (co_flags) ()
|
||||
* ? byte: bytecode instructions, ends with '0x53', '0x0' (83, 0): RETURN_VALUE (co_code)
|
||||
* ? byte(PyTuple): constants used in the code (co_consts)
|
||||
* ? byte(PyTuple): names used in the code (co_names)
|
||||
* ? byte(PyTuple): variable names defined in the code, include params (PyTuple) (co_varnames)
|
||||
* ? byte(PyTuple): variables captured from the outer scope (co_freevars)
|
||||
* ? byte(PyTuple): variables used in the inner closure (co_cellvars)
|
||||
* ? byte(PyUnicode or PyShortAscii): file name, where it was loaded from (co_filename)
|
||||
* ? byte(PyUnicode or PyShortAscii): the name of code itself, default is \<module\> (co_name)
|
||||
* ?~?+3 byte(u32): number of first line (co_firstlineno)
|
||||
* ? byte(bytes): line table, represented by PyStringObject? (co_lnotab)
|
||||
|
||||
## PyTupleObject
|
||||
|
||||
* 0 byte: 0x29 (means ')')
|
||||
* 01~04 byte(u32): number of tuple items
|
||||
* ? byte(PyObject): items
|
||||
|
||||
## PyStringObject
|
||||
|
||||
* If I use a character other than ascii, does it become PyUnicode?
|
||||
* "あ", "𠮷", and "α" are PyUnicode (no longer used?)
|
||||
|
||||
* 0 byte: 0x73 (means 's')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyUnicodeObject
|
||||
|
||||
* 0 byte: 0x75 (means 'u')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyShortAsciiObject
|
||||
|
||||
* This is called short, but even if there are more than 100 characters, this will still short
|
||||
* or rather, there is no ascii that is not short (is short a data type?)
|
||||
|
||||
* 0 byte: 0xFA (means 'z')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyInternedObject
|
||||
|
||||
* interned objects are registered in a dedicated map and can be compared with is
|
||||
* String, for example, can be compared in constant time regardless of its length
|
||||
|
||||
* 0 byte: 0x74 (means 't')
|
||||
|
||||
## PyShortAsciiInternedObject
|
||||
|
||||
* 0 byte: 0xDA (means 'Z')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
# Python 字节码规范
|
||||
|
||||
## 格式
|
||||
|
||||
* 0~3 byte(u32):幻数(详见common/bytecode.rs)
|
||||
* 4~7 byte(u32): 0 padding
|
||||
* 8~12 byte(u32): 时间戳
|
||||
* 13~ byte(PyCodeObject): 代码对象
|
||||
* 0~3 字节(u32):幻数(详见common/bytecode.rs)
|
||||
* 4~7 字节(u32): 0 padding
|
||||
* 8~12 字节(u32): 时间戳
|
||||
* 13~ 字节(PyCodeObject): 代码对象
|
||||
|
||||
## PyCode 对象
|
||||
|
||||
* 0 byte(u8): '0xe3' (前缀,这意味着代码的'c')
|
||||
* 01~04 byte(u32): args个数(co_argcount)
|
||||
* 05~08 byte(u32): position-only args 的数量 (co_posonlyargcount)
|
||||
* 09~12 byte(u32):仅关键字参数的数量(co_kwonlyargcount)
|
||||
* 13~16 byte(u32): 本地数 (co_nlocals)
|
||||
* 17~20 byte(u32): 栈大小(co_stacksize)
|
||||
* 21~24 byte(u32):标志(co_flags)()
|
||||
* ? byte:字节码指令,以'0x53'、'0x0'结尾(83, 0):RETURN_VALUE(co_code)
|
||||
* ? byte(PyTuple):代码中使用的常量(co_consts)
|
||||
* ? byte(PyTuple):代码中使用的名称(co_names)
|
||||
* ? byte(PyTuple):代码中定义的变量名,包括params (PyTuple) (co_varnames)
|
||||
* ? byte(PyTuple):从外部范围捕获的变量(co_freevars)
|
||||
* ? byte(PyTuple):内部闭包中使用的变量(co_cellvars)
|
||||
* ? byte(PyUnicode 或 PyShortAscii):文件名,它是从哪里加载的(co_filename)
|
||||
* ? byte(PyUnicode or PyShortAscii): 代码本身的名字,默认是\<module\> (co_name)
|
||||
* ?~?+3 byte(u32): 第一行数 (co_firstlineno)
|
||||
* ? byte(bytes):行表,用 PyStringObject? (co_lnotab)
|
||||
* 0 字节(u8): '0xe3' (前缀,这意味着代码的'c')
|
||||
* 01~04 字节(u32): args个数(co_argcount)
|
||||
* 05~08 字节(u32): position-only args 的数量 (co_posonlyargcount)
|
||||
* 09~12 字节(u32):仅关键字参数的数量(co_kwonlyargcount)
|
||||
* 13~16 字节(u32): 本地数 (co_nlocals)
|
||||
* 17~20 字节(u32): 栈大小(co_stacksize)
|
||||
* 21~24 字节(u32):标志(co_flags)()
|
||||
* ? 字节:字节码指令,以'0x53'、'0x0'结尾(83, 0):RETURN_VALUE(co_code)
|
||||
* ? 字节(PyTuple):代码中使用的常量(co_consts)
|
||||
* ? 字节(PyTuple):代码中使用的名称(co_names)
|
||||
* ? 字节(PyTuple):代码中定义的变量名,包括params (PyTuple) (co_varnames)
|
||||
* ? 字节(PyTuple):从外部范围捕获的变量(co_freevars)
|
||||
* ? 字节(PyTuple):内部闭包中使用的变量(co_cellvars)
|
||||
* ? 字节(PyUnicode 或 PyShortAscii):文件名,它是从哪里加载的(co_filename)
|
||||
* ? 字节(PyUnicode or PyShortAscii): 代码本身的名字,默认是\<module\> (co_name)
|
||||
* ?~?+3 字节(u32): 第一行数 (co_firstlineno)
|
||||
* ? 字节(bytes):行表,用 PyStringObject? (co_lnotab)
|
||||
|
||||
## PyTupleObject
|
||||
## Py 元组对象
|
||||
|
||||
* 0 byte: 0x29 (意思是:')')
|
||||
* 01~04 byte(u32): 元组项数
|
||||
* ? byte(PyObject):项目
|
||||
* 0 字节: 0x29 (意思是:`)`)
|
||||
* 01~04 字节(u32): 元组项数
|
||||
* ? 字节(PyObject):项目
|
||||
|
||||
## PyString 对象
|
||||
|
||||
* 如果我使用 ascii 以外的字符,它会变成 PyUnicode 吗?
|
||||
* “あ”、“𠮷”和“α”是 PyUnicode(不再使用?)
|
||||
* 如果我使用 ascii 以外的字符,它会变成 PyUnicode 吗?
|
||||
* “あ”、“𠮷”和“α”是 PyUnicode(不再使用?)
|
||||
|
||||
* 0 byte:0x73(表示's')
|
||||
* 1~4 byte:字符串长度
|
||||
* 5~ byte:有效载荷
|
||||
* 0 字节:0x73(表示`s`)
|
||||
* 1~4 字节:字符串长度
|
||||
* 5~ 字节:有效载荷
|
||||
|
||||
## PyUnicode 对象
|
||||
|
||||
* 0 byte:0x75(表示“u”)
|
||||
* 1~4 byte:字符串长度
|
||||
* 5~ byte:有效载荷
|
||||
* 0 字节:0x75(表示`u`)
|
||||
* 1~4 字节:字符串长度
|
||||
* 5~ 字节:有效载荷
|
||||
|
||||
## PyShortAsciiObject
|
||||
## PyShortAscii 对象
|
||||
|
||||
* 这叫短,但是即使超过100个字符,仍然会保持在短的状态
|
||||
* 或者更确切地说,没有不短的 ascii(短数据类型吗?)
|
||||
* 或者更确切地说,没有不短的 ascii(短数据类型吗?)
|
||||
|
||||
* 0 byte:0xFA(表示“z”)
|
||||
* 1~4 byte:字符串长度
|
||||
* 5~ byte:有效载荷
|
||||
* 0 字节:0xFA(表示`z`)
|
||||
* 1~4 字节:字符串长度
|
||||
* 5~ 字节:有效载荷
|
||||
|
||||
## PyInternedObject
|
||||
## PyInterned 对象
|
||||
|
||||
* 实习对象注册在专用地图中,可以与is进行比较
|
||||
* 例如字符串,无论其长度如何,都可以在恒定时间内进行比较
|
||||
|
||||
* 0 byte:0x74(表示't')
|
||||
* 0 字节:0x74(表示`t`)
|
||||
|
||||
## PyShortAsciiInternedObject
|
||||
## PyShortAsciiInterned 对象
|
||||
|
||||
* 0 byte:0xDA(表示“Z”)
|
||||
* 1~4 byte:字符串长度
|
||||
* 5~ byte:有效载荷
|
||||
* 0 字节:0xDA(表示`Z`)
|
||||
* 1~4 字节:字符串长度
|
||||
* 5~ 字节:有效载荷
|
|
@ -18,7 +18,7 @@ john["name"] # 错误:john 不可订阅
|
|||
|
||||
与 JavaScript 对象字面量的区别在于它们不能作为字符串访问。 也就是说,属性不仅仅是字符串。
|
||||
这是因为对值的访问是在编译时确定的,而且字典和记录是不同的东西。 换句话说,`{"name": "John"}` 是一个字典,`{name = "John"}` 是一个记录。
|
||||
那么我们应该如何使用字典和记录呢?
|
||||
那么我们应该如何使用字典和记录呢?
|
||||
一般来说,我们建议使用记录。 记录具有在编译时检查元素是否存在以及能够指定 __visibility_ 的优点。
|
||||
指定可见性等同于在 Java 和其他语言中指定公共/私有。 有关详细信息,请参阅 [可见性](./15_visibility.md) 了解详细信息。
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ Person = Class {
|
|||
```
|
||||
|
||||
元素属性(在记录中定义的属性)和类型属性(也称为实例/类属性,尤其是在类的情况下)是完全不同的东西。 类型属性是类型本身的属性。 当一个类型的元素本身没有所需的属性时,它指的是一个类型属性。 元素属性是元素直接拥有的唯一属性。
|
||||
为什么要进行这种区分? 如果所有属性都是元素属性,那么在创建对象时复制和初始化所有属性将是低效的。
|
||||
为什么要进行这种区分? 如果所有属性都是元素属性,那么在创建对象时复制和初始化所有属性将是低效的。
|
||||
此外,以这种方式划分属性明确了诸如“该属性是共享的”和“该属性是分开持有的”之类的角色。
|
||||
|
||||
下面的例子说明了这一点。 `species` 属性对所有实例都是通用的,因此将其用作类属性更自然。 但是,属性 `name` 应该是实例属性,因为每个实例都应该单独拥有它。
|
||||
|
|
|
@ -66,7 +66,7 @@ StrMoreThan4 = Inherit StrMoreThan3, Excluding: StrWithLen N | N == 3
|
|||
另外,覆盖不能改变方法的类型。它必须是原始类型的子类型。
|
||||
如果你重写了一个被另一个方法引用的方法,你也必须重写所有被引用的方法。
|
||||
|
||||
为什么这个条件是必要的?这是因为重写不仅会改变一种方法的行为,而且可能会影响另一种方法的行为。
|
||||
为什么这个条件是必要的?这是因为重写不仅会改变一种方法的行为,而且可能会影响另一种方法的行为。
|
||||
|
||||
让我们从第一个条件开始。此条件是为了防止“意外覆盖”。
|
||||
换句话说,必须使用 `Override` 装饰器来防止派生类中新定义的方法的名称与基类的名称冲突。
|
||||
|
@ -206,7 +206,7 @@ Inherited!
|
|||
虽然继承在正确使用时是一项强大的功能,但它也有一个缺点,即它往往会使类依赖关系复杂化,尤其是在使用多层或多层继承时。复杂的依赖关系会降低代码的可维护性。
|
||||
Erg 禁止多重和多层继承的原因是为了降低这种风险,并且引入了类补丁功能以降低依赖关系的复杂性,同时保留继承的“添加功能”方面。
|
||||
|
||||
那么,反过来说,应该在哪里使用继承呢?一个指标是何时需要“基类的语义子类型”。
|
||||
那么,反过来说,应该在哪里使用继承呢?一个指标是何时需要“基类的语义子类型”。
|
||||
Erg 允许类型系统自动进行部分子类型确定(例如,Nat,其中 Int 大于或等于 0)。
|
||||
但是,例如,仅依靠 Erg 的类型系统很难创建“表示有效电子邮件地址的字符串类型”。您可能应该对普通字符串执行验证。然后,我们想为已通过验证的字符串对象添加某种“保证”。这相当于向下转换为继承的类。将 `Str object` 向下转换为 `ValidMailAddressStr` 与验证字符串是否采用正确的电子邮件地址格式是一一对应的。
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ assert MonthsClass.new(12) in Months
|
|||
assert MonthsClass.new(2).name() == "february"
|
||||
```
|
||||
|
||||
## 最后,我应该使用哪个,NST 还是 SST?
|
||||
## 最后,我应该使用哪个,NST 还是 SST?
|
||||
|
||||
如果您无法决定使用哪一个,我们的建议是 NST。
|
||||
SST 需要抽象技能来编写在任何用例中都不会崩溃的代码。 好的抽象可以带来高生产力,但错误的抽象(外观上的共性)会导致适得其反的结果。(NST 可以通过故意将抽象保持在最低限度来降低这种风险。如果您不是库实现者,那么仅使用 NST 进行编码并不是一个坏主意。
|
||||
|
|
|
@ -197,7 +197,7 @@ K(0).
|
|||
|
||||
## 所有对称类型
|
||||
|
||||
上一节中定义的 `id` 函数是一个可以是任何类型的函数。 那么 `id` 函数本身的类型是什么?
|
||||
上一节中定义的 `id` 函数是一个可以是任何类型的函数。 那么 `id` 函数本身的类型是什么?
|
||||
|
||||
```python
|
||||
print! classof(id) # |T: Type| T -> T
|
||||
|
@ -229,7 +229,7 @@ assert (|T: Type| T -> T) == (|U: Type| U -> U)
|
|||
```
|
||||
|
||||
您可能还记得封闭的较小/开放的较大。
|
||||
但为什么会这样呢? 为了更好地理解,让我们考虑每个实例。
|
||||
但为什么会这样呢? 为了更好地理解,让我们考虑每个实例。
|
||||
|
||||
```python
|
||||
# id: |T: Type| T -> T
|
||||
|
@ -260,7 +260,7 @@ id_int_fn(f3: Int -> Int): (Int -> Int) = f
|
|||
|
||||
## 量化类型和依赖类型
|
||||
|
||||
依赖类型和量化类型(多态函数类型)之间有什么关系,它们之间有什么区别?
|
||||
依赖类型和量化类型(多态函数类型)之间有什么关系,它们之间有什么区别?
|
||||
我们可以说依赖类型是一种接受参数的类型,而量化类型是一种赋予参数任意性的类型。
|
||||
|
||||
重要的一点是封闭的多态类型本身没有类型参数。例如,多态函数类型`|T| T -> T` 是一个接受多态函数 __only__ 的类型,它的定义是封闭的。您不能使用其类型参数`T`来定义方法等。
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
> __Warning__:本文档已过时,一般包含错误。
|
||||
|
||||
Erg 允许您定义接受各种类型的函数,例如 `id|T|(x: T): T = x`,即多相关。
|
||||
那么,我们可以定义一个接受多相关的函数吗?
|
||||
那么,我们可以定义一个接受多相关的函数吗?
|
||||
比如这样的函数(注意这个定义是错误的):
|
||||
|
||||
```python
|
||||
|
|
|
@ -17,7 +17,7 @@ f x: T = ...
|
|||
f|X <: T| x: X = ...
|
||||
```
|
||||
|
||||
事实上,existential 类型被 for-all 类型所取代。 那么为什么会有存在类型这样的东西呢?
|
||||
事实上,existential 类型被 for-all 类型所取代。 那么为什么会有存在类型这样的东西呢?
|
||||
首先,正如我们在上面看到的,存在类型不涉及类型变量,这简化了类型规范。
|
||||
此外,由于可以删除类型变量,因此如果它是一个全推定类型,则可以构造一个等级为 2 或更高的类型。
|
||||
|
||||
|
|
|
@ -129,9 +129,9 @@ Fn2 T, U: Type = Patch T -> U
|
|||
Fn2(T, U).
|
||||
f self = ...
|
||||
|
||||
(Int -> Int).f() # 选择了哪一个?
|
||||
(Int -> Int).f() # 选择了哪一个?
|
||||
```
|
||||
在上面的示例中,方法 `f` 会选择哪个补丁?
|
||||
在上面的示例中,方法 `f` 会选择哪个补丁?
|
||||
天真,似乎选择了`Fn T`,但是`Fn2 T,U`也是可以的,`Option T`原样包含`T`,所以任何类型都适用,`Container K,T`也匹配`->(Int, Int)`,即 `Container(`->`, Int)` 为 `Int -> Int`。因此,上述所有四个修复程序都是可能的选择。
|
||||
|
||||
在这种情况下,根据以下优先标准选择修复程序。
|
||||
|
|
|
@ -57,7 +57,7 @@ id x: Int = x
|
|||
id x: Ratio = x
|
||||
...
|
||||
id "str" # 类型错误:没有为 Str 实现 id
|
||||
# 但是……但是……这个错误是从哪里来的?
|
||||
# 但是……但是……这个错误是从哪里来的?
|
||||
```
|
||||
|
||||
其次,它与默认参数不兼容。 当具有默认参数的函数被重载时,会出现一个优先级的问题。
|
||||
|
@ -66,7 +66,7 @@ id "str" # 类型错误:没有为 Str 实现 id
|
|||
f x: Int = ...
|
||||
f(x: Int, y := 0) = ...
|
||||
|
||||
f(1) # 选择哪个?
|
||||
f(1) # 选择哪个?
|
||||
```
|
||||
|
||||
此外,它与声明不兼容。
|
||||
|
@ -85,7 +85,7 @@ f(x: Ratio): Int = ...
|
|||
# 同 `f = x -> body`
|
||||
f x = body
|
||||
|
||||
# 一样……什么?
|
||||
# 一样……什么?
|
||||
f x: Int = x
|
||||
f x: Ratio = x
|
||||
```
|
||||
|
|
|
@ -16,7 +16,7 @@ normal_area.push(new NormalMember())
|
|||
console.log(vip_area) # [NormalMember]
|
||||
```
|
||||
|
||||
一个 NormalMember 已进入 vip_area。 这是一个明显的错误,但是出了什么问题?
|
||||
一个 NormalMember 已进入 vip_area。 这是一个明显的错误,但是出了什么问题?
|
||||
原因是共享引用 [denatured](./variance.md)。 `normal_area` 是通过复制 `vip_area` 来创建的,但是这样做的时候类型已经改变了。
|
||||
但是 `VIPMember` 继承自 `NormalMember`,所以 `VIPMember[] <: NormalMember[]`,这不是问题。
|
||||
关系 `VIPMember[] <: NormalMember[]` 适用于不可变对象。 但是,如果您执行上述破坏性操作,则会出现故障。
|
||||
|
|
|
@ -39,7 +39,7 @@ print! L # <kind L>
|
|||
```python
|
||||
i = j = 1 # SyntaxError: 不允許多次賦值
|
||||
print!(x=1) # SyntaxError: cannot use `=` in function arguments
|
||||
# 提示:您的意思是關鍵字參數(`x: 1`)嗎?
|
||||
# 提示:您的意思是關鍵字參數(`x: 1`)嗎?
|
||||
if True, do:
|
||||
i = 0 # SyntaxError: 塊不能被賦值表達式終止
|
||||
```
|
||||
|
|
|
@ -3,11 +3,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/compiler/TODO_recov_suggest.md&commit_hash=d15cbbf7b33df0f78a575cff9679d84c36ea3ab1)
|
||||
|
||||
* `1 or 2`, `1 and 2` => `{1, 2}`?
|
||||
* `U = Inherit T` => 非類類型不能被繼承,或者`U = Class T`?
|
||||
* `Int and Str` => 不允許多重繼承,或者`Int or Str`?
|
||||
* `: [1, 2]` => `: {1, 2}`?
|
||||
* `: [Int, 2]` => `: [Int; 2]`?
|
||||
* `[Int; Str]` => `(Int, Str)`(Tuple) 還是 `[Int: Str]`(Dict)?
|
||||
* `{x: Int}` => `{x = Int}`?
|
||||
* `{x = Int}!` => `{x = Int!}`?
|
||||
* `U = Inherit T` => 非類類型不能被繼承,或者`U = Class T`?
|
||||
* `Int and Str` => 不允許多重繼承,或者`Int or Str`?
|
||||
* `: [1, 2]` => `: {1, 2}`?
|
||||
* `: [Int, 2]` => `: [Int; 2]`?
|
||||
* `[Int; Str]` => `(Int, Str)`(Tuple) 還是 `[Int: Str]`(Dict)?
|
||||
* `{x: Int}` => `{x = Int}`?
|
||||
* `{x = Int}!` => `{x = Int!}`?
|
||||
* `ref! immut_expr` => `ref! !immut_expr`?
|
|
@ -4,4 +4,4 @@
|
|||
|
||||
* `t = {(record type)}` => `T = {(record type)}`?(只有定義為常量的類型才能用于類型說明)
|
||||
* `{I: Int | ...}!` => `{I: Int! | ...}`
|
||||
* for/while 塊中的`return x`(`x != ()`) => `f::return`(外部塊)?
|
||||
* for/while 塊中的`return x`(`x != ()`) => `f::return`(外部塊)?
|
|
@ -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/compiler/trait_method_resolving.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
`Nat` 是零個或多個`Int`,`Int` 的子類型。
|
||||
`Nat` 在 Python 類層次結構中不存在。 我想知道 Erg 是如何解決這個補丁方法的?
|
||||
`Nat` 在 Python 類層次結構中不存在。 我想知道 Erg 是如何解決這個補丁方法的?
|
||||
|
||||
```python
|
||||
1.times do:
|
||||
|
@ -19,7 +19,7 @@ Erg 在 `Int` 的 MRO 中有 `Int`、`Object`。它來自 Python(Python 中的`i
|
|||
|
||||
整數顯然應該在其超類型中包含實數、復數甚至整數,但這一事實并沒有出現在 Python 兼容層中。
|
||||
然而,`1 in Complex` 和 `1 in Num` 在 Erg 中實際上是 `True`。
|
||||
至于`Complex`,即使是與`Int`沒有繼承關系的類,也被判斷為類型兼容。這到底是怎么回事?
|
||||
至于`Complex`,即使是與`Int`沒有繼承關系的類,也被判斷為類型兼容。這到底是怎么回事?
|
||||
|
||||
~
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Erg 代碼如何轉譯成 Python 代碼?
|
||||
# Erg 代碼如何轉譯成 Python 代碼?
|
||||
|
||||
[](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/transpile.md&commit_hash=06f8edc9e2c0cee34f6396fd7c64ec834ffb5352)
|
||||
|
||||
|
|
|
@ -45,9 +45,9 @@ switch_lang!(
|
|||
|
||||
## FAQ
|
||||
|
||||
Q:像這樣的指定是什么意思?A:{RED} 及更高版本將顯示為紅色。重新啟動交互渲染。
|
||||
Q:像這樣的指定是什么意思?A:{RED} 及更高版本將顯示為紅色。重新啟動交互渲染。
|
||||
|
||||
Q:如果想添加自己的語言,該如何替換部分?答:目前支持以下語言。
|
||||
Q:如果想添加自己的語言,該如何替換部分?答:目前支持以下語言。
|
||||
|
||||
* "english"(默認設置)
|
||||
* "japanese" (日語)
|
||||
|
|
|
@ -3,26 +3,26 @@
|
|||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/faq_general.md&commit_hash=521426cba21ed8b6eae5aff965dd14ef99af1228)
|
||||
|
||||
此常見問題解答適用於一般 Erg 初學者。
|
||||
對於個別(常見)技術問題,請參閱 [此處](./faq_technical.md) 了解個別(常見)技術問題,以及
|
||||
對於個別(常見)技術問題,請參閱 [此處](./faq_technical.md) 了解個別(常見)技術問題,以及
|
||||
[這裡](./dev_guide/faq_syntax.md) 了解更多信息。
|
||||
|
||||
## Erg 是 Python 兼容語言是什么意思?
|
||||
## Erg 是 Python 兼容語言是什么意思?
|
||||
|
||||
~~A:Erg的可執行系統EVM(Erg VirtualMachine)執行Erg字節碼,是Python字節碼的擴展。它在 Python 字節碼中引入了靜態類型系統和其他特性(例如向不帶參數的指令引入參數,以及在自由編號中實現唯一指令)。這讓 Erg 可以無縫調用 Python 代碼并快速執行。~~
|
||||
|
||||
A: Erg 代碼被轉譯成 Python 字節碼。也就是說,它運行在與 Python 相同的解釋器上。最初,我們計劃開發一個兼容 Cpython 的解釋器,并將其與編譯器結合起來形成“Erg”。但是,由于處理系統的發展遠遠落后于編譯器,我們決定提前只發布編譯器(但解釋器仍在開發中)。
|
||||
|
||||
## 哪些語言影響了Erg?
|
||||
## 哪些語言影響了Erg?
|
||||
|
||||
我們受到的語言多于我們雙手所能指望的數量,但 Python、Rust、Nim 和 Haskell 的影響最大。
|
||||
我們從 Python 繼承了許多語義,從 Rust 繼承了面向表達式和 trait,從 Nim 繼承了過程,從 Haskell 繼承了函數式編程相關的特性。
|
||||
|
||||
## 已經有一些語言可以調用Python,比如Julia。為什麼要創建Erg?
|
||||
## 已經有一些語言可以調用Python,比如Julia。為什麼要創建Erg?
|
||||
|
||||
答:Erg 設計的動機之一是擁有一種易于使用且具有強大類型系統的語言。即具有類型推斷、Kind、依賴類型等的語言。
|
||||
Julia 是可以有類型的,但它確實是一種動態類型語言,不具備靜態類型語言的編譯時錯誤檢測優勢。
|
||||
|
||||
## Erg 支持多種編程風格,包括函數式和面向對象的編程。這不是與 Python 的“應該有一種——最好只有一種——明顯的方法”相反嗎?
|
||||
## Erg 支持多種編程風格,包括函數式和面向對象的編程。這不是與 Python 的“應該有一種——最好只有一種——明顯的方法”相反嗎?
|
||||
|
||||
答:在 Erg 中,該術語是在更狹窄的上下文中使用的。例如,Erg API 中一般沒有別名;在這種情況下,Erg是“唯一一種方式”。
|
||||
在更大的上下文中,例如 FP 或 OOP,只有一種做事方式并不一定很方便。
|
||||
|
@ -32,7 +32,7 @@ Julia 是可以有類型的,但它確實是一種動態類型語言,不具
|
|||
如果程序員沒有一些東西,他們會自己創造它們。因此,我們認為將它們作為標準提供會更好。
|
||||
這也符合 Python 的“含電池”概念。
|
||||
|
||||
## Erg 這個名字的由來是什么?
|
||||
## Erg 這個名字的由來是什么?
|
||||
|
||||
它以cgs單位系統中的能量單位erg命名。它具有雙重含義:一種為程序員提供能量的符合人體工程學的語言。
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
## 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代碼使用跟踪垃圾回收內存管理模型
|
||||
|
||||
|
@ -13,28 +13,28 @@
|
|||
__注意__: Erg 引入所有權系統的動機不是像 Rust 那樣“不依賴 GC 的內存管理”。
|
||||
首先,Erg 目前唯一可用前端編譯Erg為Python字節碼,因此使用了 GC。
|
||||
Erg 所有權系統的目標是“可變狀態的本地化”。 Erg 有一個附屬於可變對象的所有權概念。
|
||||
這是因為共享可變狀態容易出現錯誤,甚至違反類型安全(參見 [此處](../syntax/type/advanced/shared.md#共享参考))。這是一個判斷決定。
|
||||
這是因為共享可變狀態容易出現錯誤,甚至違反類型安全(參見 [此處](../syntax/type/advanced/shared.md#共享参考))。這是一個判斷決定。
|
||||
|
||||
## 為什麼類型參數要大括號 || 而不是 <> 或 []?
|
||||
## 為什麼類型參數要大括號 || 而不是 <> 或 []?
|
||||
|
||||
這是因為 `<>` 和 `[]` 會導致語法衝突。
|
||||
|
||||
```python
|
||||
# []版
|
||||
id[T: Type] [t]: [T] = t
|
||||
y = id[Int] # 這是一個功能嗎?
|
||||
y = id[Int] # 這是一個功能嗎?
|
||||
# <>版
|
||||
id<T: Type> {t: T} = t
|
||||
y = (id<Int, 1> 1) # 這是一個元組嗎?
|
||||
y = (id<Int, 1> 1) # 這是一個元組嗎?
|
||||
# {}版
|
||||
id{T: Type} {t: T} = t
|
||||
y = id{Int} # 這是一個功能嗎?
|
||||
y = id{Int} # 這是一個功能嗎?
|
||||
# ||版
|
||||
id|T: Type| t: T = t
|
||||
y = id|Int| # OK
|
||||
```
|
||||
|
||||
## {i=1} 的類型為 {i=Int},但在 OCaml 等環境中為 {i:Int}。為什麼 Erg 採用前者的語法?
|
||||
## {i=1} 的類型為 {i=Int},但在 OCaml 等環境中為 {i:Int}。為什麼 Erg 採用前者的語法?
|
||||
|
||||
Erg 設計為將類型本身也視為值。
|
||||
|
||||
|
@ -49,11 +49,11 @@ S = {.i = Int}
|
|||
assert S.i == Int
|
||||
```
|
||||
|
||||
## 你打算在 Erg 中實現宏嗎?
|
||||
## 你打算在 Erg 中實現宏嗎?
|
||||
|
||||
目前沒有。宏觀大致分為四個目的。第一個是編譯時計算。這在 Erg 中由編譯時函數負責。第二,代碼執行的延遲。這可以用 do 塊來代替。第三個是處理通用化,對此多相關數和全稱類型是比宏觀更好的解決方案。第四個是自動生成代碼,但這會造成可讀性的下降,所以我們不敢在 Erg 中實現。因此,宏的大部分功能都由 Erg 型系統承擔,因此沒有動力進行部署。
|
||||
|
||||
## 為什麼 Erg 沒有異常機制?
|
||||
## 為什麼 Erg 沒有異常機制?
|
||||
|
||||
因為在許多情況下,使用 `Result` 類型進行錯誤處理是更好的解決方案。 `Result` 類型是相對較新的編程語言中使用的常見錯誤處理技術。
|
||||
|
||||
|
@ -79,11 +79,11 @@ try!:
|
|||
|
||||
此外,Erg 沒有引入異常機制的另一個原因是它計劃引入並行編程的功能。這是因為異常機制與並行執行不兼容(例如,如果並行執行導致多個異常,則很難處理)。
|
||||
|
||||
## Erg 似乎消除了 Python 被認為是壞做法的功能,但為什麼沒有取消繼承?
|
||||
## Erg 似乎消除了 Python 被認為是壞做法的功能,但為什麼沒有取消繼承?
|
||||
|
||||
Python 的庫中有一些類設計為繼承,如果完全取消繼承,這些操作就會出現問題。然而,由於 Erg 的類默認為 final,並且原則上禁止多重和多層繼承,因此繼承的使用相對安全。
|
||||
|
||||
## 為什麼多相關數的子類型推理默認指向記名trait?
|
||||
## 為什麼多相關數的子類型推理默認指向記名trait?
|
||||
|
||||
默認情況下,指向結構托盤會使類型指定變得複雜,並且可能會混合程序員的非預期行為。
|
||||
|
||||
|
@ -96,21 +96,21 @@ f|T| x, y: T = x + y - x
|
|||
g|T| x, y: T = x + y - x
|
||||
```
|
||||
|
||||
## Erg 是否實現了定義自己的運算符的功能?
|
||||
## Erg 是否實現了定義自己的運算符的功能?
|
||||
|
||||
A:沒有那個計劃。最重要的原因是,如果允許定義自己的運算符,就會出現如何處理組合順序的問題。可以定義自己的運算符的 Scala 和 Haskell 等都有不同的對應,但這可以看作是可能產生解釋差異的語法的證據。此外,獨立運算符還有一個缺點,那就是可能產生可讀性較低的代碼。
|
||||
|
||||
## 為什麼 Erg 取消了 += 這樣的擴展賦值運算符?
|
||||
## 為什麼 Erg 取消了 += 這樣的擴展賦值運算符?
|
||||
|
||||
首先,Erg 中沒有變量可變性。換句話說,它不能被重新分配。一旦一個對象綁定到一個變量,它就會一直綁定到該變量,直到它超出範圍並被釋放。 Erg 中的可變性意味著對象可變性。一旦你知道了這一點,故事就很簡單了。例如,`i += 1` 表示 `i = i + 1`,但這樣的語法是非法的,因為變量沒有被重新分配。 Erg 的另一個設計原則是操作符不應該有副作用。 Python 大多是這樣,但是對於某些對象,例如 Dict,擴展賦值運算符會改變對象的內部狀態。這不是一個非常漂亮的設計。
|
||||
這就是擴展賦值運算符完全過時的原因。
|
||||
|
||||
## 為什麼 Erg 在語法上特別對待有副作用的過程?
|
||||
## 為什麼 Erg 在語法上特別對待有副作用的過程?
|
||||
|
||||
副作用的局部化是代碼維護的一個關鍵因素。
|
||||
|
||||
但是,確實也不是沒有方法可以不在語言上特殊對待副作用。例如,可以用代數效果(類型系統上的功能)替代過程。但這樣的合一併不總是正確的。例如,Haskell 沒有對字符串進行特殊處理,只是一個字符數組,但這種抽像是錯誤的。
|
||||
|
||||
什麼情況下,可以說合一化是錯的?一個指標是“是否會因其合一而難以看到錯誤信息”。 Erg 設計師發現,將副作用特殊處理會使錯誤消息更容易閱讀。
|
||||
什麼情況下,可以說合一化是錯的?一個指標是“是否會因其合一而難以看到錯誤信息”。 Erg 設計師發現,將副作用特殊處理會使錯誤消息更容易閱讀。
|
||||
|
||||
Erg 有一個強大的類型系統,但並不是所有的類型都決定了它。如果這樣做了,你的下場就跟 Java 試圖用類來控制一切一樣。
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
|
||||
有關如何確定語法的更多信息,請參閱 [此處](./dev_guide/faq_syntax.md) 了解基礎語法決策,以及 [此處](./dev_guide/../faq_general.md)。
|
||||
|
||||
## Erg 中有異常機制嗎?
|
||||
## Erg 中有異常機制嗎?
|
||||
|
||||
答:不會。Erg 使用 `Result` 類型代替。請參閱 [此處](./dev_guide/faq_syntax.md) 了解 Erg 沒有異常機制的原因。
|
||||
|
||||
## Erg 是否有與 TypeScript 的 `Any` 等價的類型?
|
||||
## Erg 是否有與 TypeScript 的 `Any` 等價的類型?
|
||||
|
||||
答:不,沒有。所有對象都至少屬于 `Object` 類,但是這種類型只提供了一組最小的屬性,所以你不能像使用 Any 那樣對它做任何你想做的事情。
|
||||
`Object` 類通過`match` 等動態檢查轉換為所需的類型。它與Java 和其他語言中的`Object` 是同一種。
|
||||
在 Erg 世界中,沒有像 TypeScript 那樣的混亂和絕望,其中 API 定義是“Any”。
|
||||
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么區別?
|
||||
## Never、{}、None、()、NotImplemented 和 Ellipsis 有什么區別?
|
||||
|
||||
A:`Never` 是一種“不可能”的類型。產生運行時錯誤的子例程將“Never”(或“Never”的合并類型)作為其返回類型。該程序將在檢測到這一點后立即停止。盡管 `Never` 類型在定義上也是所有類型的子類,但 `Never` 類型的對象永遠不會出現在 Erg 代碼中,也永遠不會被創建。 `{}` 等價于 `Never`。
|
||||
`Ellipsis` 是一個表示省略號的對象,來自 Python。
|
||||
|
@ -24,12 +24,12 @@ A:`Never` 是一種“不可能”的類型。產生運行時錯誤的子例
|
|||
`None` 是 `NoneType` 的一個實例。它通常與 `Option` 類型一起使用。
|
||||
`()` 是一個單元類型和它自己的一個實例。當您想要返回“無意義的值”(例如過程的返回值)時使用它。
|
||||
|
||||
## 為什么 `x = p!()` 有效但 `f() = p!()` 會導致 EffectError?
|
||||
## 為什么 `x = p!()` 有效但 `f() = p!()` 會導致 EffectError?
|
||||
|
||||
`!` 不是副作用產品的標記,而是可能導致副作用的對象。
|
||||
過程 `p!` 和可變類型 `T!` 會引起副作用,但如果 `p!()` 的返回值是 `Int` 類型,它本身就不再引起副作用。
|
||||
|
||||
## 當我嘗試使用 Python API 時,對于在 Python 中有效的代碼,我在 Erg 中收到類型錯誤。這是什么意思?
|
||||
## 當我嘗試使用 Python API 時,對于在 Python 中有效的代碼,我在 Erg 中收到類型錯誤。這是什么意思?
|
||||
|
||||
A:Erg API 的類型盡可能接近 Python API 規范,但有些情況無法完全表達。
|
||||
此外,根據規范有效但被認為不合需要的輸入(例如,在應該輸入 int 時輸入浮點數)可能會被 Erg 開發團隊酌情視為類型錯誤。
|
|
@ -26,7 +26,7 @@ Python并不清楚可變和不可變/堆和值對象之間的區別,因此您
|
|||
另外,如果你想讓你自己的類不可變,你必須經歷一個乏味的過程。
|
||||
|
||||
```python
|
||||
# 你能相信這段代碼對過去的 Python 版本有效嗎?
|
||||
# 你能相信這段代碼對過去的 Python 版本有效嗎?
|
||||
i = 256
|
||||
assert i is 256
|
||||
i = 257
|
||||
|
|
|
@ -56,14 +56,14 @@ stack.push(consts[namei])
|
|||
fastlocals[namei] = stack.pop()
|
||||
可能對應于頂層的 STORE_NAME
|
||||
假定未引用(或單個)變量由此存儲
|
||||
全局空間有自己的指令是為了優化嗎?
|
||||
全局空間有自己的指令是為了優化嗎?
|
||||
|
||||
## LOAD_FAST(名稱索引)
|
||||
|
||||
```python
|
||||
stack.push(fastlocals[namei])
|
||||
```
|
||||
fastlocals 是變量名嗎?
|
||||
fastlocals 是變量名嗎?
|
||||
|
||||
## LOAD_CLOSURE(名稱索引)
|
||||
|
||||
|
|
|
@ -1,145 +1,74 @@
|
|||
# Python bytecode specification
|
||||
# Python 字節碼規範
|
||||
|
||||
[](https://gezf7g7pd5.execute-api.ap-northeast-1.amazonaws.com/default/source_up_to_date?owner=erg-lang&repos=erg&ref=main&path=doc/EN/python/bytecode_specification.md&commit_hash=9f6a4a43fcf7e4f58cabe6e5a7546820fd9f5ff4)
|
||||
|
||||
## Format
|
||||
|
||||
* 0~3 byte(u32): magic number (see common/bytecode.rs for details)
|
||||
* 4~7 byte(u32): 0 padding
|
||||
* 8~12 byte(u32): timestamp
|
||||
* 13~ byte(PyCodeObject): code object
|
||||
|
||||
## PyCodeObject
|
||||
|
||||
* 0 byte(u8): '0xe3' (prefix, this means code's 'c')
|
||||
* 01~04 byte(u32): number of args (co_argcount)
|
||||
* 05~08 byte(u32): number of position-only args (co_posonlyargcount)
|
||||
* 09~12 byte(u32): number of keyword-only args (co_kwonlyargcount)
|
||||
* 13~16 byte(u32): number of locals (co_nlocals)
|
||||
* 17~20 byte(u32): stack size (co_stacksize)
|
||||
* 21~24 byte(u32): flags (co_flags) ()
|
||||
* ? byte: bytecode instructions, ends with '0x53', '0x0' (83, 0): RETURN_VALUE (co_code)
|
||||
* ? byte(PyTuple): constants used in the code (co_consts)
|
||||
* ? byte(PyTuple): names used in the code (co_names)
|
||||
* ? byte(PyTuple): variable names defined in the code, include params (PyTuple) (co_varnames)
|
||||
* ? byte(PyTuple): variables captured from the outer scope (co_freevars)
|
||||
* ? byte(PyTuple): variables used in the inner closure (co_cellvars)
|
||||
* ? byte(PyUnicode or PyShortAscii): file name, where it was loaded from (co_filename)
|
||||
* ? byte(PyUnicode or PyShortAscii): the name of code itself, default is \<module\> (co_name)
|
||||
* ?~?+3 byte(u32): number of first line (co_firstlineno)
|
||||
* ? byte(bytes): line table, represented by PyStringObject? (co_lnotab)
|
||||
|
||||
## PyTupleObject
|
||||
|
||||
* 0 byte: 0x29 (means ')')
|
||||
* 01~04 byte(u32): number of tuple items
|
||||
* ? byte(PyObject): items
|
||||
|
||||
## PyStringObject
|
||||
|
||||
* If I use a character other than ascii, does it become PyUnicode?
|
||||
* "あ", "??", and "α" are PyUnicode (no longer used?)
|
||||
|
||||
* 0 byte: 0x73 (means 's')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyUnicodeObject
|
||||
|
||||
* 0 byte: 0x75 (means 'u')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyShortAsciiObject
|
||||
|
||||
* This is called short, but even if there are more than 100 characters, this will still short
|
||||
* or rather, there is no ascii that is not short (is short a data type?)
|
||||
|
||||
* 0 byte: 0xFA (means 'z')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
## PyInternedObject
|
||||
|
||||
* interned objects are registered in a dedicated map and can be compared with is
|
||||
* String, for example, can be compared in constant time regardless of its length
|
||||
|
||||
* 0 byte: 0x74 (means 't')
|
||||
|
||||
## PyShortAsciiInternedObject
|
||||
|
||||
* 0 byte: 0xDA (means 'Z')
|
||||
* 1~4 byte: length of string
|
||||
* 5~ byte: payload
|
||||
|
||||
# Python 字節碼規范
|
||||
|
||||
## 格式
|
||||
|
||||
* 0~3 byte(u32):幻數(詳見common/bytecode.rs)
|
||||
* 4~7 byte(u32): 0 padding
|
||||
* 8~12 byte(u32): 時間戳
|
||||
* 13~ byte(PyCodeObject): 代碼對象
|
||||
* 0~3 字節(u32):幻數(詳見common/bytecode.rs)
|
||||
* 4~7 字節(u32): 0 padding
|
||||
* 8~12 字節(u32): 時間戳
|
||||
* 13~ 字節(PyCodeObject): 代碼對象
|
||||
|
||||
## PyCode 對象
|
||||
|
||||
* 0 byte(u8): '0xe3' (前綴,這意味著代碼的'c')
|
||||
* 01~04 byte(u32): args個數(co_argcount)
|
||||
* 05~08 byte(u32): position-only args 的數量 (co_posonlyargcount)
|
||||
* 09~12 byte(u32):僅關鍵字參數的數量(co_kwonlyargcount)
|
||||
* 13~16 byte(u32): 本地數 (co_nlocals)
|
||||
* 17~20 byte(u32): 棧大小(co_stacksize)
|
||||
* 21~24 byte(u32):標志(co_flags)()
|
||||
* ? byte:字節碼指令,以'0x53'、'0x0'結尾(83, 0):RETURN_VALUE(co_code)
|
||||
* ? byte(PyTuple):代碼中使用的常量(co_consts)
|
||||
* ? byte(PyTuple):代碼中使用的名稱(co_names)
|
||||
* ? byte(PyTuple):代碼中定義的變量名,包括params (PyTuple) (co_varnames)
|
||||
* ? byte(PyTuple):從外部范圍捕獲的變量(co_freevars)
|
||||
* ? byte(PyTuple):內部閉包中使用的變量(co_cellvars)
|
||||
* ? byte(PyUnicode 或 PyShortAscii):文件名,它是從哪里加載的(co_filename)
|
||||
* ? byte(PyUnicode or PyShortAscii): 代碼本身的名字,默認是\<module\> (co_name)
|
||||
* ?~?+3 byte(u32): 第一行數 (co_firstlineno)
|
||||
* ? byte(bytes):行表,用 PyStringObject? (co_lnotab)
|
||||
* 0 字節(u8): '0xe3' (前綴,這意味著代碼的'c')
|
||||
* 01~04 字節(u32): args個數(co_argcount)
|
||||
* 05~08 字節(u32): position-only args 的數量 (co_posonlyargcount)
|
||||
* 09~12 字節(u32):僅關鍵字參數的數量(co_kwonlyargcount)
|
||||
* 13~16 字節(u32): 本地數 (co_nlocals)
|
||||
* 17~20 字節(u32): 棧大小(co_stacksize)
|
||||
* 21~24 字節(u32):標誌(co_flags)()
|
||||
* ? 字節:字節碼指令,以'0x53'、'0x0'結尾(83, 0):RETURN_VALUE(co_code)
|
||||
* ? 字節(PyTuple):代碼中使用的常量(co_consts)
|
||||
* ? 字節(PyTuple):代碼中使用的名稱(co_names)
|
||||
* ? 字節(PyTuple):代碼中定義的變量名,包括params (PyTuple) (co_varnames)
|
||||
* ? 字節(PyTuple):從外部範圍捕獲的變量(co_freevars)
|
||||
* ? 字節(PyTuple):內部閉包中使用的變量(co_cellvars)
|
||||
* ? 字節(PyUnicode 或 PyShortAscii):文件名,它是從哪裡加載的(co_filename)
|
||||
* ? 字節(PyUnicode or PyShortAscii): 代碼本身的名字,默認是\<module\> (co_name)
|
||||
* ?~?+3 字節(u32): 第一行數 (co_firstlineno)
|
||||
* ? 字節(bytes):行表,用 PyStringObject? (co_lnotab)
|
||||
|
||||
## PyTupleObject
|
||||
## Py 元組對象
|
||||
|
||||
* 0 byte: 0x29 (意思是:')')
|
||||
* 01~04 byte(u32): 元組項數
|
||||
* ? byte(PyObject):項目
|
||||
* 0 字節: 0x29 (意思是:`)`)
|
||||
* 01~04 字節(u32): 元組項數
|
||||
* ? 字節(PyObject):項目
|
||||
|
||||
## PyString 對象
|
||||
|
||||
* 如果我使用 ascii 以外的字符,它會變成 PyUnicode 嗎?
|
||||
* “あ”、“??”和“α”是 PyUnicode(不再使用?)
|
||||
* 如果我使用 ascii 以外的字符,它會變成 PyUnicode 嗎?
|
||||
* “あ”、“𠮷”和“α”是 PyUnicode(不再使用?)
|
||||
|
||||
* 0 byte:0x73(表示's')
|
||||
* 1~4 byte:字符串長度
|
||||
* 5~ byte:有效載荷
|
||||
* 0 字節:0x73(表示`s`)
|
||||
* 1~4 字節:字符串長度
|
||||
* 5~ 字節:有效載荷
|
||||
|
||||
## PyUnicode 對象
|
||||
|
||||
* 0 byte:0x75(表示“u”)
|
||||
* 1~4 byte:字符串長度
|
||||
* 5~ byte:有效載荷
|
||||
* 0 字節:0x75(表示`u`)
|
||||
* 1~4 字節:字符串長度
|
||||
* 5~ 字節:有效載荷
|
||||
|
||||
## PyShortAsciiObject
|
||||
## PyShortAscii 對象
|
||||
|
||||
* 這叫短,但是即使超過100個字符,仍然會保持在短的狀態
|
||||
* 或者更確切地說,沒有不短的 ascii(短數據類型嗎?)
|
||||
* 或者更確切地說,沒有不短的 ascii(短數據類型嗎?)
|
||||
|
||||
* 0 byte:0xFA(表示“z”)
|
||||
* 1~4 byte:字符串長度
|
||||
* 5~ byte:有效載荷
|
||||
* 0 字節:0xFA(表示`z`)
|
||||
* 1~4 字節:字符串長度
|
||||
* 5~ 字節:有效載荷
|
||||
|
||||
## PyInternedObject
|
||||
## PyInterned 對象
|
||||
|
||||
* 實習對象注冊在專用地圖中,可以與is進行比較
|
||||
* 例如字符串,無論其長度如何,都可以在恒定時間內進行比較
|
||||
* 實習對象註冊在專用地圖中,可以與is進行比較
|
||||
* 例如字符串,無論其長度如何,都可以在恆定時間內進行比較
|
||||
|
||||
* 0 byte:0x74(表示't')
|
||||
* 0 字節:0x74(表示`t`)
|
||||
|
||||
## PyShortAsciiInternedObject
|
||||
## PyShortAsciiInterned 對象
|
||||
|
||||
* 0 byte:0xDA(表示“Z”)
|
||||
* 1~4 byte:字符串長度
|
||||
* 5~ byte:有效載荷
|
||||
* 0 字節:0xDA(表示`Z`)
|
||||
* 1~4 字節:字符串長度
|
||||
* 5~ 字節:有效載荷
|
|
@ -18,7 +18,7 @@ john["name"] # 錯誤:john 不可訂閱
|
|||
|
||||
與 JavaScript 對象字面量的區別在于它們不能作為字符串訪問。 也就是說,屬性不僅僅是字符串。
|
||||
這是因為對值的訪問是在編譯時確定的,而且字典和記錄是不同的東西。 換句話說,`{"name": "John"}` 是一個字典,`{name = "John"}` 是一個記錄。
|
||||
那么我們應該如何使用字典和記錄呢?
|
||||
那么我們應該如何使用字典和記錄呢?
|
||||
一般來說,我們建議使用記錄。 記錄具有在編譯時檢查元素是否存在以及能夠指定 __visibility_ 的優點。
|
||||
指定可見性等同于在 Java 和其他語言中指定公共/私有。 有關詳細信息,請參閱 [可見性](./15_visibility.md) 了解詳細信息。
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@ Person = Class {
|
|||
```
|
||||
|
||||
元素屬性(在記錄中定義的屬性)和類型屬性(也稱為實例/類屬性,尤其是在類的情況下)是完全不同的東西。類型屬性是類型本身的屬性。當一個類型的元素本身沒有所需的屬性時,它指的是一個類型屬性。元素屬性是元素直接擁有的唯一屬性。
|
||||
為什麼要進行這種區分?如果所有屬性都是元素屬性,那麼在創建對象時復制和初始化所有屬性將是低效的。
|
||||
為什麼要進行這種區分?如果所有屬性都是元素屬性,那麼在創建對象時復制和初始化所有屬性將是低效的。
|
||||
此外,以這種方式劃分屬性明確了諸如“該屬性是共享的”和“該屬性是分開持有的”之類的角色。
|
||||
|
||||
下面的例子說明了這一點。 `species` 屬性對所有實例都是通用的,因此將其用作類屬性更自然。但是,屬性 `name` 應該是實例屬性,因為每個實例都應該單獨擁有它。
|
||||
|
|
|
@ -66,7 +66,7 @@ StrMoreThan4 = Inherit StrMoreThan3, Excluding: StrWithLen N | N == 3
|
|||
另外,覆蓋不能改變方法的類型。它必須是原始類型的子類型。
|
||||
如果你重寫了一個被另一個方法引用的方法,你也必須重寫所有被引用的方法。
|
||||
|
||||
為什么這個條件是必要的?這是因為重寫不僅會改變一種方法的行為,而且可能會影響另一種方法的行為。
|
||||
為什么這個條件是必要的?這是因為重寫不僅會改變一種方法的行為,而且可能會影響另一種方法的行為。
|
||||
|
||||
讓我們從第一個條件開始。此條件是為了防止“意外覆蓋”。
|
||||
換句話說,必須使用 `Override` 裝飾器來防止派生類中新定義的方法的名稱與基類的名稱沖突。
|
||||
|
@ -206,7 +206,7 @@ Inherited!
|
|||
雖然繼承在正確使用時是一項強大的功能,但它也有一個缺點,即它往往會使類依賴關系復雜化,尤其是在使用多層或多層繼承時。復雜的依賴關系會降低代碼的可維護性。
|
||||
Erg 禁止多重和多層繼承的原因是為了降低這種風險,并且引入了類補丁功能以降低依賴關系的復雜性,同時保留繼承的“添加功能”方面。
|
||||
|
||||
那么,反過來說,應該在哪里使用繼承呢?一個指標是何時需要“基類的語義子類型”。
|
||||
那么,反過來說,應該在哪里使用繼承呢?一個指標是何時需要“基類的語義子類型”。
|
||||
Erg 允許類型系統自動進行部分子類型確定(例如,Nat,其中 Int 大于或等于 0)。
|
||||
但是,例如,僅依靠 Erg 的類型系統很難創建“表示有效電子郵件地址的字符串類型”。您可能應該對普通字符串執行驗證。然后,我們想為已通過驗證的字符串對象添加某種“保證”。這相當于向下轉換為繼承的類。將 `Str object` 向下轉換為 `ValidMailAddressStr` 與驗證字符串是否采用正確的電子郵件地址格式是一一對應的。
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ assert MonthsClass.new(12) in Months
|
|||
assert MonthsClass.new(2).name() == "february"
|
||||
```
|
||||
|
||||
## 最后,我應該使用哪個,NST 還是 SST?
|
||||
## 最后,我應該使用哪個,NST 還是 SST?
|
||||
|
||||
如果您無法決定使用哪一個,我們的建議是 NST。
|
||||
SST 需要抽象技能來編寫在任何用例中都不會崩潰的代碼。 好的抽象可以帶來高生產力,但錯誤的抽象(外觀上的共性)會導致適得其反的結果。(NST 可以通過故意將抽象保持在最低限度來降低這種風險。如果您不是庫實現者,那么僅使用 NST 進行編碼并不是一個壞主意。
|
||||
|
|
|
@ -197,7 +197,7 @@ K(0).
|
|||
|
||||
## 所有對稱類型
|
||||
|
||||
上一節中定義的 `id` 函數是一個可以是任何類型的函數。 那么 `id` 函數本身的類型是什么?
|
||||
上一節中定義的 `id` 函數是一個可以是任何類型的函數。 那么 `id` 函數本身的類型是什么?
|
||||
|
||||
```python
|
||||
print! classof(id) # |T: Type| T -> T
|
||||
|
@ -229,7 +229,7 @@ assert (|T: Type| T -> T) == (|U: Type| U -> U)
|
|||
```
|
||||
|
||||
您可能還記得封閉的較小/開放的較大。
|
||||
但為什么會這樣呢? 為了更好地理解,讓我們考慮每個實例。
|
||||
但為什么會這樣呢? 為了更好地理解,讓我們考慮每個實例。
|
||||
|
||||
```python
|
||||
# id: |T: Type| T -> T
|
||||
|
@ -260,7 +260,7 @@ id_int_fn(f3: Int -> Int): (Int -> Int) = f
|
|||
|
||||
## 量化類型和依賴類型
|
||||
|
||||
依賴類型和量化類型(多態函數類型)之間有什么關系,它們之間有什么區別?
|
||||
依賴類型和量化類型(多態函數類型)之間有什么關系,它們之間有什么區別?
|
||||
我們可以說依賴類型是一種接受參數的類型,而量化類型是一種賦予參數任意性的類型。
|
||||
|
||||
重要的一點是封閉的多態類型本身沒有類型參數。例如,多態函數類型`|T| T -> T` 是一個接受多態函數 __only__ 的類型,它的定義是封閉的。您不能使用其類型參數`T`來定義方法等。
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
> __Warning__:本文檔已過時,一般包含錯誤。
|
||||
|
||||
Erg 允許您定義接受各種類型的函數,例如 `id|T|(x: T): T = x`,即多相關。
|
||||
那么,我們可以定義一個接受多相關的函數嗎?
|
||||
那么,我們可以定義一個接受多相關的函數嗎?
|
||||
比如這樣的函數(注意這個定義是錯誤的):
|
||||
|
||||
```python
|
||||
|
|
|
@ -17,7 +17,7 @@ f x: T = ...
|
|||
f|X <: T| x: X = ...
|
||||
```
|
||||
|
||||
事實上,existential 類型被 for-all 類型所取代。 那么為什么會有存在類型這樣的東西呢?
|
||||
事實上,existential 類型被 for-all 類型所取代。 那么為什么會有存在類型這樣的東西呢?
|
||||
首先,正如我們在上面看到的,存在類型不涉及類型變量,這簡化了類型規范。
|
||||
此外,由于可以刪除類型變量,因此如果它是一個全推定類型,則可以構造一個等級為 2 或更高的類型。
|
||||
|
||||
|
|
|
@ -129,9 +129,9 @@ Fn2 T, U: Type = Patch T -> U
|
|||
Fn2(T, U).
|
||||
f self = ...
|
||||
|
||||
(Int -> Int).f() # 選擇了哪一個?
|
||||
(Int -> Int).f() # 選擇了哪一個?
|
||||
```
|
||||
在上面的示例中,方法 `f` 會選擇哪個補丁?
|
||||
在上面的示例中,方法 `f` 會選擇哪個補丁?
|
||||
天真,似乎選擇了`Fn T`,但是`Fn2 T,U`也是可以的,`Option T`原樣包含`T`,所以任何類型都適用,`Container K,T`也匹配`->(Int, Int)`,即 `Container(`->`, Int)` 為 `Int -> Int`。因此,上述所有四個修復程序都是可能的選擇。
|
||||
|
||||
在這種情況下,根據以下優先標準選擇修復程序。
|
||||
|
|
|
@ -57,7 +57,7 @@ id x: Int = x
|
|||
id x: Ratio = x
|
||||
...
|
||||
id "str" # 類型錯誤:沒有為 Str 實現 id
|
||||
# 但是……但是……這個錯誤是從哪里來的?
|
||||
# 但是……但是……這個錯誤是從哪里來的?
|
||||
```
|
||||
|
||||
其次,它與默認參數不兼容。 當具有默認參數的函數被重載時,會出現一個優先級的問題。
|
||||
|
@ -66,7 +66,7 @@ id "str" # 類型錯誤:沒有為 Str 實現 id
|
|||
f x: Int = ...
|
||||
f(x: Int, y := 0) = ...
|
||||
|
||||
f(1) # 選擇哪個?
|
||||
f(1) # 選擇哪個?
|
||||
```
|
||||
|
||||
此外,它與聲明不兼容。
|
||||
|
@ -85,7 +85,7 @@ f(x: Ratio): Int = ...
|
|||
# 同 `f = x -> body`
|
||||
f x = body
|
||||
|
||||
# 一樣……什么?
|
||||
# 一樣……什么?
|
||||
f x: Int = x
|
||||
f x: Ratio = x
|
||||
```
|
||||
|
|
|
@ -16,7 +16,7 @@ normal_area.push(new NormalMember())
|
|||
console.log(vip_area) # [NormalMember]
|
||||
```
|
||||
|
||||
一個 NormalMember 已進入 vip_area。 這是一個明顯的錯誤,但是出了什么問題?
|
||||
一個 NormalMember 已進入 vip_area。 這是一個明顯的錯誤,但是出了什么問題?
|
||||
原因是共享引用 [denatured](./variance.md)。 `normal_area` 是通過復制 `vip_area` 來創建的,但是這樣做的時候類型已經改變了。
|
||||
但是 `VIPMember` 繼承自 `NormalMember`,所以 `VIPMember[] <: NormalMember[]`,這不是問題。
|
||||
關系 `VIPMember[] <: NormalMember[]` 適用于不可變對象。 但是,如果您執行上述破壞性操作,則會出現故障。
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue