1
1
/-
2
+ --#--
2
3
# Embedding DSLs By Elaboration
3
4
5
+ --#--
6
+ # エラボレーションによる DSL の埋め込み
7
+
8
+ --#--
4
9
In this chapter we will learn how to use elaboration to build a DSL. We will not
5
10
explore the full power of `MetaM`, and simply gesture at how to get access to
6
11
this low-level machinery.
7
12
13
+ --#--
14
+ この章では DSL を構築するためにどのようにエラボレーションを使うかについて学びます。ここでは `MetaM` の全機能を探求することはせずに、単にこの低レベルの機構にアクセスする方法を紹介します。
15
+
16
+ --#--
8
17
More precisely, we shall enable Lean to understand the syntax of
9
18
[ IMP ] (http://concrete-semantics.org/concrete-semantics.pdf),
10
19
which is a simple imperative language, often used for teaching operational and
11
- denotational semantics.
20
+ denotational semantics.
21
+
22
+ --#--
23
+ 具体的には、[ IMP ] (http://concrete-semantics.org/concrete-semantics.pdf) の構文を Lean が理解できるようにします。これは単純な命令型言語で、操作的意味論・表示的意味論の教育によく用いられます。
12
24
25
+ --#--
13
26
We are not going to define everything with the same encoding that the book does.
14
27
For instance, the book defines arithmetic expressions and boolean expressions.
15
28
We, will take a different path and just define generic expressions that take
16
29
unary or binary operators.
17
30
31
+ --#--
32
+ この本と同じエンコーディングですべてを定義するつもりはありません。例えば、この本では算術式や真偽値の式を定義しています。本章では別の方針を取り、単項演算子や二項演算子を取る一般的な式を定義します。
33
+
34
+ --#--
18
35
This means that we will allow weirdnesses like `1 + true`! But it will simplify
19
36
the encoding, the grammar and consequently the metaprogramming didactic.
20
37
38
+ --#--
39
+ つまり、`1 + true` のような奇妙さを許容します!しかし、これはエンコーディングや文法、ひいてはメタプログラミングの教材として単純化することになります。
40
+
41
+ --#--
21
42
## Defining our AST
22
43
44
+ --#--
45
+ ## AST の定義
46
+
47
+ --#--
23
48
We begin by defining our atomic literal value.
49
+ --#--
50
+ まず、アトミックなリテラルの値を定義します。
24
51
-/
25
52
26
53
import Lean
@@ -31,16 +58,31 @@ inductive IMPLit
31
58
| nat : Nat → IMPLit
32
59
| bool : Bool → IMPLit
33
60
61
+ --#--
34
62
/- This is our only unary operator -/
63
+ --#--
64
+ /-
65
+ 次は唯一の単項演算子です。
66
+ -/
35
67
inductive IMPUnOp
36
68
| not
37
69
70
+ --#--
38
71
/- These are our binary operations. -/
72
+ --#--
73
+ /-
74
+ これらは二項演算子です。
75
+ -/
39
76
40
77
inductive IMPBinOp
41
78
| and | add | less
42
79
80
+ --#--
43
81
/- Now we define the expressions that we want to handle. -/
82
+ --#--
83
+ /-
84
+ ここで、今回扱いたい式を定義します。
85
+ -/
44
86
45
87
inductive IMPExpr
46
88
| lit : IMPLit → IMPExpr
@@ -49,8 +91,11 @@ inductive IMPExpr
49
91
| bin : IMPBinOp → IMPExpr → IMPExpr → IMPExpr
50
92
51
93
/-
94
+ --#--
52
95
And finally the commands of our language. Let's follow the book and say that
53
96
"each piece of a program is also a program":
97
+ --#--
98
+ そして最後に、言語のコマンドです。この本に従って、「プログラムの各部分もプログラムである」としましょう:
54
99
-/
55
100
56
101
inductive IMPProgram
@@ -61,11 +106,18 @@ inductive IMPProgram
61
106
| While : IMPExpr → IMPProgram → IMPProgram
62
107
63
108
/-
109
+ --#--
64
110
## Elaborating literals
65
111
112
+ --#--
113
+ ### リテラルのエラボレート
114
+
115
+ --#--
66
116
Now that we have our data types, let's elaborate terms of `Syntax` into
67
117
terms of `Expr`. We begin by defining the syntax and an elaboration function for
68
118
literals.
119
+ --#--
120
+ さて、データ型ができたので、`Syntax` の項を `Expr` の項にエラボレートしましょう。まずはリテラルの構文とそのエラボレーション関数を定義します。
69
121
-/
70
122
71
123
declare_syntax_cat imp_lit
@@ -74,8 +126,12 @@ syntax "true" : imp_lit
74
126
syntax "false" : imp_lit
75
127
76
128
def elabIMPLit : Syntax → MetaM Expr
129
+ --#--
77
130
-- `mkAppM` creates an `Expr.app`, given the function `Name` and the args
78
131
-- `mkNatLit` creates an `Expr` from a `Nat`
132
+ --#--
133
+ -- `mkAppM` は対象の関数の `Name` とその引数から `Expr.app` を作成する
134
+ -- `mkNatLit` は `Nat` から `Expr` を作成する
79
135
| `(imp_lit| $n:num) => mkAppM ``IMPLit.nat #[mkNatLit n.getNat]
80
136
| `(imp_lit| true ) => mkAppM ``IMPLit.bool #[.const ``Bool.true []]
81
137
| `(imp_lit| false ) => mkAppM ``IMPLit.bool #[.const ``Bool.false []]
@@ -88,14 +144,26 @@ elab "test_elabIMPLit " l:imp_lit : term => elabIMPLit l
88
144
#reduce test_elabIMPLit false -- IMPLit.bool true
89
145
90
146
/-
147
+ --#--
91
148
## Elaborating expressions
92
149
150
+ --#--
151
+ ## 式のエラボレート
152
+
153
+ --#--
93
154
In order to elaborate expressions, we also need a way to elaborate our unary and
94
155
binary operators.
95
156
157
+ --#--
158
+ 式をエラボレートするために、単項演算子と二項演算子をエラボレートする方法も必要です。
159
+
160
+ --#--
96
161
Notice that these could very much be pure functions (`Syntax → Expr`), but we're
97
162
staying in `MetaM` because it allows us to easily throw an error for match
98
- completion.-/
163
+ completion.
164
+ --#--
165
+ これらは純粋関数(`Syntax → Expr`)にすることもできますが、マッチの網羅時に例外を簡単に投げられるように `MetaM` に留まることとします。
166
+ -/
99
167
100
168
declare_syntax_cat imp_unop
101
169
syntax "not" : imp_unop
@@ -115,7 +183,12 @@ def elabIMPBinOp : Syntax → MetaM Expr
115
183
| `(imp_binop| <) => return .const ``IMPBinOp.less []
116
184
| _ => throwUnsupportedSyntax
117
185
186
+ --#--
118
187
/-Now we define the syntax for expressions: -/
188
+ --#--
189
+ /-
190
+ ここで式の構文を定義します:
191
+ -/
119
192
120
193
declare_syntax_cat imp_expr
121
194
syntax imp_lit : imp_expr
@@ -124,24 +197,33 @@ syntax imp_unop imp_expr : imp_expr
124
197
syntax imp_expr imp_binop imp_expr : imp_expr
125
198
126
199
/-
200
+ --#--
127
201
Let's also allow parentheses so the IMP programmer can denote their parsing
128
202
precedence.
203
+ --#--
204
+ IMP プログラマがパースの優先順位を示せるように括弧も許可しましょう。
129
205
-/
130
206
131
207
syntax "(" imp_expr ")" : imp_expr
132
208
133
209
/-
210
+ --#--
134
211
Now we can elaborate our expressions. Note that expressions can be recursive.
135
212
This means that our `elabIMPExpr` function will need to be recursive! We'll need
136
213
to use `partial` because Lean can't prove the termination of `Syntax`
137
214
consumption alone.
215
+ --#--
216
+ これで式をエラボレートできます。式は再帰的であることに注意してください。これは `elabIMPExpr` 関数が再帰的である必要があることを意味します!Lean は `Syntax` の消費だけでは終了を証明できないため `partial` を使う必要があります。
138
217
-/
139
218
140
219
partial def elabIMPExpr : Syntax → MetaM Expr
141
220
| `(imp_expr| $l:imp_lit) => do
142
221
let l ← elabIMPLit l
143
222
mkAppM ``IMPExpr.lit #[l]
223
+ --#--
144
224
-- `mkStrLit` creates an `Expr` from a `String`
225
+ --#--
226
+ -- `mkStrLit` は `String` から `Expr` を作成する
145
227
| `(imp_expr| $i:ident) => mkAppM ``IMPExpr.var #[mkStrLit i.getId.toString]
146
228
| `(imp_expr| $b:imp_unop $e:imp_expr) => do
147
229
let b ← elabIMPUnOp b
@@ -167,9 +249,16 @@ elab "test_elabIMPExpr " e:imp_expr : term => elabIMPExpr e
167
249
-- IMPExpr.bin IMPBinOp.add (IMPExpr.lit (IMPLit.nat 1)) (IMPExpr.lit (IMPLit.bool true))
168
250
169
251
/-
252
+ --#--
170
253
## Elaborating programs
171
254
255
+ --#--
256
+ ## プログラムのエラボレート
257
+
258
+ --#--
172
259
And now we have everything we need to elaborate our IMP programs!
260
+ --#--
261
+ そしてこれで IMP プログラムをエラボレートするために必要なものがすべて手に入りました!
173
262
-/
174
263
175
264
declare_syntax_cat imp_program
@@ -203,8 +292,11 @@ partial def elabIMPProgram : Syntax → MetaM Expr
203
292
| _ => throwUnsupportedSyntax
204
293
205
294
/-
295
+ --#--
206
296
And we can finally test our full elaboration pipeline. Let's use the following
207
297
syntax:
298
+ --#--
299
+ そしてついにエラボレーションのパイプラインを完全にテストすることができます。以下の構文を使ってみましょう:
208
300
-/
209
301
210
302
elab ">>" p:imp_program "<<" : term => elabIMPProgram p
0 commit comments