1
- /- # Extra: Pretty Printing
1
+ /-
2
+ --#--
3
+ # Extra: Pretty Printing
4
+ --#--
5
+ # 付録:プリティプリント
6
+ --#--
2
7
The pretty printer is what Lean uses to present terms that have been
3
8
elaborated to the user. This is done by converting the `Expr`s back into
4
9
`Syntax` and then even higher level pretty printing datastructures. This means
@@ -7,6 +12,10 @@ there has to be code that tells it how to do that.
7
12
In the big picture, the pretty printer consists of three parts run in the
8
13
order they are listed in:
9
14
15
+ --#--
16
+ プリティプリンタとは、Lean がエラボレートした項をユーザに提示するために使用されるものです。これは `Expr` を `Syntax` に変換し、さらに高レベルのプリティプリント用データ構造に戻すことで行われます。これは Lean が `Expr` を作成する際に使用した実際の `Syntax` を思い出すわけではないことを意味します:もしそうであればその方法を指示するコードがあるはずですから。全体像として、プリティプリンタは3つの部分から構成されています:
17
+
18
+ --#--
10
19
- the **[ delaborator ] (https://github.com/leanprover/lean4/tree/master/src/Lean/PrettyPrinter/Delaborator)**
11
20
this will be our main interest since we can easily extend it with our own code.
12
21
Its job is to turn `Expr` back into `Syntax`.
@@ -16,18 +25,35 @@ order they are listed in:
16
25
responsible for turning the parenthesized `Syntax` tree into a `Format` object that contains
17
26
more pretty printing information like explicit whitespaces
18
27
28
+ --#--
29
+ - **[ デラボレータ ] (https://github.com/leanprover/lean4/tree/master/src/Lean/PrettyPrinter/Delaborator)** 、この部分は簡単に独自のコードで拡張ができることもあり最も興味深い部分です。このパートの仕事は `Expr` を `Syntax` に戻すことです。
30
+ - **[ parenthesizer ] (https://github.com/leanprover/lean4/blob/master/src/Lean/PrettyPrinter/Parenthesizer.lean)** は `Syntax` 木に便利だと思われる位置に括弧を追加する役割を持ちます。
31
+ - **[ フォーマッタ ] (https://github.com/leanprover/lean4/blob/master/src/Lean/PrettyPrinter/Formatter.lean)** は括弧が付けられた `Syntax` 木に明示的なスペースを入れるなどのよりプリティプリントな情報を含む `Format` オブジェクトに変換する役割を持ちます。
32
+
33
+ --#--
19
34
## Delaboration
35
+ --#--
36
+ ## デラボレーション
37
+ --#--
20
38
As its name suggests, the delaborator is in a sense the opposite of the
21
39
elaborator. The job of the delaborator is to take an `Expr` produced by
22
40
the elaborator and turn it back into a `Syntax` which, if elaborated,
23
41
should produce an `Expr` that behaves equally to the input one.
24
42
43
+ --#--
44
+ その名前が示すように、デラボレータはある意味においてエラボレータの反対です。デラボレータの仕事は、エラボレータが生成した `Expr` を受け取り、`Syntax` に戻すことです。ここで生成される `Syntax` はエラボレートされると、デラボレータに入力された `Expr` と同じものを出力しなければなりません。
45
+
46
+ --#--
25
47
Delaborators have the type `Lean.PrettyPrinter.Delaborator.Delab`. This
26
48
is an alias for `DelabM Syntax`, where `DelabM` is the delaboration monad.
27
49
All of this machinery is defined [ here ] (https://github.com/leanprover/lean4/blob/master/src/Lean/PrettyPrinter/Delaborator/Basic.lean).
28
50
`DelabM` provides us with quite a lot of options you can look up in the documentation
29
51
(TODO: Docs link). We will merely highlight the most relevant parts here.
30
52
53
+ --#--
54
+ デラボレータは `Lean.PrettyPrinter.Delaborator.Delab` という型を持ちます。これは `DelabM Syntax` のエイリアスで、`DelabM` はデラボレーションのためのモナドです。この機構についてはすべて [ ここ ] (https://github.com/leanprover/lean4/blob/master/src/Lean/PrettyPrinter/Delaborator/Basic.lean) にて定義されています。`DelabM` は非常に多くのオプションを提供しており、これはドキュメントから探すことができます(TODO: Docs link)。ここでは単に最も関連性のある部分を強調します。
55
+
56
+ --#--
31
57
- It has a `MonadQuotation` instance which allows us to declare `Syntax` objects
32
58
using the familiar quotation syntax.
33
59
- It can run `MetaM` code.
@@ -36,13 +62,26 @@ All of this machinery is defined [here](https://github.com/leanprover/lean4/blob
36
62
- You can obtain the current subexpression using `SubExpr.getExpr`. There is
37
63
also an entire API defined around this concept in the `SubExpr` module.
38
64
65
+ --#--
66
+ - `MonadQuotation` インスタンスを持っており、おなじみのquotation構文を使って `Syntax` オブジェクトを宣言することができます。
67
+ - `MetaM` のコードを実行することができます。
68
+ - 例外を投げるための `MonadExcept` インスタンスを持ちます。
69
+ - `whenPPOption` のような関数を使うことで `pp` オプションを操作することができます。
70
+ - 現在の部分式を取得するには `SubExpr.getExpr` を使用します。また、`SubExpr` モジュールには、この概念を扱う API 全体が定義されています。
71
+
72
+ --#--
39
73
### Making our own
74
+ --#--
75
+ ### 独自のデラボレータを作る
76
+ --#--
40
77
Like so many things in metaprogramming the elaborator is based on an attribute,
41
78
in this case the `delab` one. `delab` expects a `Name` as an argument,
42
79
this name has to start with the name of an `Expr` constructor, most commonly
43
80
`const` or `app`. This constructor name is then followed by the name of the
44
81
constant we want to delaborate. For example, if we want to delaborate a function
45
82
`foo` in a special way we would use `app.foo`. Let's see this in action:
83
+ --#--
84
+ メタプログラミングの多くのものと同様に、エラボレータは属性に基づいており、今回の場合では `delab` です。`delab` は引数として `Name` を受け取り、この名前は `Expr` コンストラクタの名前で始まる必要があり、最も一般的あなのは `const` か `app` です。このコンストラクタ名の後にデラボレートしたい定数の名前が続きます。例えば、関数 `foo` を特別な方法でデラボレートしたい場合は `app.foo` を使います。これを実際にやってみましょう:
46
85
-/
47
86
48
87
import Lean
@@ -59,9 +98,12 @@ def delabFoo : Delab := do
59
98
#check foo 13 -- 1 : Nat, full applications are also pretty printed this way
60
99
61
100
/-!
101
+ --#--
62
102
This is obviously not a good delaborator since reelaborating this `Syntax`
63
103
will not yield the same `Expr`. Like with many other metaprogramming
64
104
attributes we can also overload delaborators:
105
+ --#--
106
+ この `Syntax` を再度エラボレートしても同じ `Expr` は得られないため、明らかに良いデラボレータではありません。他の多くのメタプログラミングの属性と同様に、デラボレータをオーバーロードすることもできます:
65
107
-/
66
108
67
109
@[delab app.foo]
@@ -71,10 +113,13 @@ def delabfoo2 : Delab := do
71
113
#check foo -- 2 : Nat → Nat
72
114
73
115
/-!
116
+ --#--
74
117
The mechanism for figuring out which one to use is the same as well. The
75
118
delaborators are tried in order, in reverse order of registering, until one
76
119
does not throw an error, indicating that it "feels unresponsible for the `Expr`".
77
120
In the case of delaborators, this is done using `failure`:
121
+ --#--
122
+ それを使うかを判断するメカニズムも同じです。デラボレータは登録された順番の逆順に、「`Expr` に対して責任が無いと感じる」ことを示すエラーを投げないものまで試行されます。デラボレータの場合、これは `failure` を使って行われます:
78
123
-/
79
124
80
125
@[delab app.foo]
@@ -85,8 +130,11 @@ def delabfoo3 : Delab := do
85
130
#check foo -- 2 : Nat → Nat, still 2 since 3 failed
86
131
87
132
/-!
133
+ --#--
88
134
In order to write a proper delaborator for `foo`, we will have to use some
89
135
slightly more advanced machinery though:
136
+ --#--
137
+ `foo` のための適切なデラボレータを書くためにはもう少し高度な機構を使う必要があります:
90
138
-/
91
139
92
140
@[delab app.foo]
@@ -101,9 +149,14 @@ def delabfooFinal : Delab := do
101
149
#check foo -- 2 : Nat → Nat, still 2 since 3 failed
102
150
103
151
/-!
152
+ --#--
104
153
Can you extend `delabFooFinal` to also account for non full applications?
105
154
155
+ --#--
156
+ 読者は `delabFooFinal` を拡張して、完全でない適用も考慮することができるでしょうか?
157
+
106
158
## Unexpanders
159
+ --#--
107
160
While delaborators are obviously quite powerful it is quite often not necessary
108
161
to use them. If you look in the Lean compiler for `@[delab` or rather `@[builtin_delab`
109
162
(a special version of the `delab` attribute for compiler use, we don't care about it),
@@ -115,21 +168,35 @@ they are of type `Lean.PrettyPrinter.Unexpander` which in turn is an alias for
115
168
are supposed to be the inverse of macros. The `UnexpandM` monad is quite a lot
116
169
weaker than `DelabM` but it still has:
117
170
171
+ --#--
172
+ デラボレータは明らかに強力ですが、使う必要がないことも良くあります。Lean コンパイラにて `@[delab` か `@[builtin_delab`(コンパイラ用の特別バージョンの `delab` 属性)を探してみるとほとんど出てこないことがわかるでしょう。というのも、プリティプリントの大部分はいわゆる unexpander によって行われるからです。デラボレータとは異なり、これらは `Lean.PrettyPrinter.Unexpander` 型で、これは `Syntax → Lean.PrettyPrinter.UnexpandM Syntax` のエイリアスです。見ての通り、これらは `Syntax` から `Syntax` への変換で、マクロの逆であることを除けばマクロによく似ています。`UnexpandM` モナドは `DelabM` よりもかなり弱いですが、それでも下記の機能を持ちます:
173
+
174
+ --#--
118
175
- `MonadQuotation` for syntax quotations
119
176
- The ability to throw errors, although not very informative ones: `throw ()`
120
177
is the only valid one
121
178
179
+ --#--
180
+ - syntax quotation のための `MonadQuotation`
181
+ - 例外の送出機能、ただこれはあまり有益なものではありません:唯一有効なのは `throw ()` だけです。
182
+
183
+ --#--
122
184
Unexpanders are always specific to applications of one constant. They are registered
123
185
using the `app_unexpander` attribute, followed by the name of said constant. The unexpander
124
186
is passed the entire application of the constant after the `Expr` has been delaborated,
125
187
without implicit arguments. Let's see this in action:
188
+ --#--
189
+ unexpander は常にある1つの定数の適用に対して固有です。これらは `app_unexpander` 属性と、それに続く対象の定数名を使って登録されます。unexpander には暗黙の引数無しで `Expr` がデラボレートされた後に、定数の適用全体が渡されます。これを実際に見てみましょう:
126
190
-/
127
191
128
192
def myid {α : Type } (x : α) := x
129
193
130
194
@[app_unexpander myid]
131
195
def unexpMyId : Unexpander
196
+ --#--
132
197
-- hygiene disabled so we can actually return `id` without macro scopes etc.
198
+ --#--
199
+ -- 健全性を無効にすることで、マクロスコープなどを使わずに `id` を実際に返すことができる。
133
200
| `(myid $arg) => set_option hygiene false in `(id $arg)
134
201
| `(myid) => pure $ mkIdent `id
135
202
| _ => throw ()
@@ -138,15 +205,25 @@ def unexpMyId : Unexpander
138
205
#check myid -- id : ?m.3870 → ?m.3870
139
206
140
207
/-!
208
+ --#--
141
209
For a few nice examples of unexpanders you can take a look at
142
210
[ NotationExtra ] (https://github.com/leanprover/lean4/blob/master/src/Init/NotationExtra.lean)
143
211
212
+ --#--
213
+ unexpander についていくつかの良例は [ NotationExtra ] (https://github.com/leanprover/lean4/blob/master/src/Init/NotationExtra.lean) を参照してください。
214
+
215
+ --#--
144
216
### Mini project
217
+ --#--
218
+ ### ミニプロジェクト
219
+ --#--
145
220
As per usual, we will tackle a little mini project at the end of the chapter.
146
221
This time we build our own unexpander for a mini programming language.
147
222
Note that many ways to define syntax already have generation of the required
148
223
pretty printer code built-in, e.g. `infix`, and `notation` (however not `macro_rules`).
149
224
So, for easy syntax, you will never have to do this yourself.
225
+ --#--
226
+ いつものように、章の最後にてちょっとしたミニプロジェクトに取り組んでみます。今回はミニプログラミング言語のための独自の unexpander を作ります。`infix` や `notation` のような構文を定義するための多くの方法には必要なプリティプリンタコードを生成する機能がすでに組み込まれていることに注意してください(ただし、`macro_rules` には含まれていません)。そのため、簡単な構文であれば、自分でこれを行う必要はないでしょう。
150
227
-/
151
228
152
229
declare_syntax_cat lang
@@ -180,8 +257,11 @@ instance : Coe Ident (TSyntax `lang) where
180
257
]
181
258
182
259
/-!
260
+ --#--
183
261
As you can see, the pretty printing output right now is rather ugly to look at.
184
262
We can do better with an unexpander:
263
+ --#--
264
+ 見ての通り、現時点の表示される出力はかなり醜いものになっています。unexpander を使えばもっとよくなります:
185
265
-/
186
266
187
267
@[app_unexpander LangExpr.numConst]
@@ -218,7 +298,10 @@ def unexpandLet : Unexpander
218
298
]
219
299
220
300
/-!
301
+ --#--
221
302
That's much better! As always, we encourage you to extend the language yourself
222
303
with things like parenthesized expressions, more data values, quotations for
223
304
`term` or whatever else comes to your mind.
305
+ --#--
306
+ この方がずっと良いです!いつものように読者は、括弧でくくられた式や、より多くのデータ値、`term` の引用など思いついたものを使って自分で言語を拡張することをお勧めします。
224
307
-/
0 commit comments