Skip to content
This repository was archived by the owner on Jan 5, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 94 additions & 2 deletions lean/main/08_dsls.lean
Original file line number Diff line number Diff line change
@@ -1,26 +1,53 @@
/-
--#--
# Embedding DSLs By Elaboration
--#--
# エラボレーションによる DSL の埋め込み
--#--
In this chapter we will learn how to use elaboration to build a DSL. We will not
explore the full power of `MetaM`, and simply gesture at how to get access to
this low-level machinery.
--#--
この章では DSL を構築するためにどのようにエラボレーションを使うかについて学びます。ここでは `MetaM` の全機能を探求することはせずに、単にこの低レベルの機構にアクセスする方法を紹介します。
--#--
More precisely, we shall enable Lean to understand the syntax of
[IMP](http://concrete-semantics.org/concrete-semantics.pdf),
which is a simple imperative language, often used for teaching operational and
denotational semantics.
denotational semantics.
--#--
具体的には、[IMP](http://concrete-semantics.org/concrete-semantics.pdf) の構文を Lean が理解できるようにします。これは単純な命令型言語で、操作的意味論・表示的意味論の教育によく用いられます。
--#--
We are not going to define everything with the same encoding that the book does.
For instance, the book defines arithmetic expressions and boolean expressions.
We, will take a different path and just define generic expressions that take
unary or binary operators.
--#--
この本と同じエンコーディングですべてを定義するつもりはありません。例えば、この本では算術式や真偽値の式を定義しています。本章では別の方針を取り、単項演算子や二項演算子を取る一般的な式を定義します。
--#--
This means that we will allow weirdnesses like `1 + true`! But it will simplify
the encoding, the grammar and consequently the metaprogramming didactic.
--#--
つまり、`1 + true` のような奇妙さを許容します!しかし、これはエンコーディングや文法、ひいてはメタプログラミングの教材として単純化することになります。
--#--
## Defining our AST
--#--
## AST の定義
--#--
We begin by defining our atomic literal value.
--#--
まず、アトミックなリテラルの値を定義します。
-/

import Lean
Expand All @@ -31,16 +58,31 @@ inductive IMPLit
| nat : Nat → IMPLit
| bool : Bool → IMPLit

--#--
/- This is our only unary operator -/
--#--
/-
次は唯一の単項演算子です。
-/
inductive IMPUnOp
| not

--#--
/- These are our binary operations. -/
--#--
/-
これらは二項演算子です。
-/

inductive IMPBinOp
| and | add | less

--#--
/- Now we define the expressions that we want to handle. -/
--#--
/-
ここで、今回扱いたい式を定義します。
-/

inductive IMPExpr
| lit : IMPLit → IMPExpr
Expand All @@ -49,8 +91,11 @@ inductive IMPExpr
| bin : IMPBinOp → IMPExpr → IMPExpr → IMPExpr

/-
--#--
And finally the commands of our language. Let's follow the book and say that
"each piece of a program is also a program":
--#--
そして最後に、言語のコマンドです。この本に従って、「プログラムの各部分もプログラムである」としましょう:
-/

inductive IMPProgram
Expand All @@ -61,11 +106,18 @@ inductive IMPProgram
| While : IMPExpr → IMPProgram → IMPProgram

/-
--#--
## Elaborating literals
--#--
### リテラルのエラボレート
--#--
Now that we have our data types, let's elaborate terms of `Syntax` into
terms of `Expr`. We begin by defining the syntax and an elaboration function for
literals.
--#--
さて、データ型ができたので、`Syntax` の項を `Expr` の項にエラボレートしましょう。まずはリテラルの構文とそのエラボレーション関数を定義します。
-/

declare_syntax_cat imp_lit
Expand All @@ -74,8 +126,12 @@ syntax "true" : imp_lit
syntax "false" : imp_lit

def elabIMPLit : Syntax → MetaM Expr
--#--
-- `mkAppM` creates an `Expr.app`, given the function `Name` and the args
-- `mkNatLit` creates an `Expr` from a `Nat`
--#--
-- `mkAppM` は対象の関数の `Name` とその引数から `Expr.app` を作成する
-- `mkNatLit` は `Nat` から `Expr` を作成する
| `(imp_lit| $n:num) => mkAppM ``IMPLit.nat #[mkNatLit n.getNat]
| `(imp_lit| true ) => mkAppM ``IMPLit.bool #[.const ``Bool.true []]
| `(imp_lit| false ) => mkAppM ``IMPLit.bool #[.const ``Bool.false []]
Expand All @@ -88,14 +144,26 @@ elab "test_elabIMPLit " l:imp_lit : term => elabIMPLit l
#reduce test_elabIMPLit false -- IMPLit.bool true

/-
--#--
## Elaborating expressions
--#--
## 式のエラボレート
--#--
In order to elaborate expressions, we also need a way to elaborate our unary and
binary operators.
--#--
式をエラボレートするために、単項演算子と二項演算子をエラボレートする方法も必要です。
--#--
Notice that these could very much be pure functions (`Syntax → Expr`), but we're
staying in `MetaM` because it allows us to easily throw an error for match
completion.-/
completion.
--#--
これらは純粋関数(`Syntax → Expr`)にすることもできますが、マッチの網羅時に例外を簡単に投げられるように `MetaM` に留まることとします。
-/

declare_syntax_cat imp_unop
syntax "not" : imp_unop
Expand All @@ -115,7 +183,12 @@ def elabIMPBinOp : Syntax → MetaM Expr
| `(imp_binop| <) => return .const ``IMPBinOp.less []
| _ => throwUnsupportedSyntax

--#--
/-Now we define the syntax for expressions: -/
--#--
/-
ここで式の構文を定義します:
-/

declare_syntax_cat imp_expr
syntax imp_lit : imp_expr
Expand All @@ -124,24 +197,33 @@ syntax imp_unop imp_expr : imp_expr
syntax imp_expr imp_binop imp_expr : imp_expr

/-
--#--
Let's also allow parentheses so the IMP programmer can denote their parsing
precedence.
--#--
IMP プログラマがパースの優先順位を示せるように括弧も許可しましょう。
-/

syntax "(" imp_expr ")" : imp_expr

/-
--#--
Now we can elaborate our expressions. Note that expressions can be recursive.
This means that our `elabIMPExpr` function will need to be recursive! We'll need
to use `partial` because Lean can't prove the termination of `Syntax`
consumption alone.
--#--
これで式をエラボレートできます。式は再帰的であることに注意してください。これは `elabIMPExpr` 関数が再帰的である必要があることを意味します!Lean は `Syntax` の消費だけでは終了を証明できないため `partial` を使う必要があります。
-/

partial def elabIMPExpr : Syntax → MetaM Expr
| `(imp_expr| $l:imp_lit) => do
let l ← elabIMPLit l
mkAppM ``IMPExpr.lit #[l]
--#--
-- `mkStrLit` creates an `Expr` from a `String`
--#--
-- `mkStrLit` は `String` から `Expr` を作成する
| `(imp_expr| $i:ident) => mkAppM ``IMPExpr.var #[mkStrLit i.getId.toString]
| `(imp_expr| $b:imp_unop $e:imp_expr) => do
let b ← elabIMPUnOp b
Expand All @@ -167,9 +249,16 @@ elab "test_elabIMPExpr " e:imp_expr : term => elabIMPExpr e
-- IMPExpr.bin IMPBinOp.add (IMPExpr.lit (IMPLit.nat 1)) (IMPExpr.lit (IMPLit.bool true))

/-
--#--
## Elaborating programs
--#--
## プログラムのエラボレート
--#--
And now we have everything we need to elaborate our IMP programs!
--#--
そしてこれで IMP プログラムをエラボレートするために必要なものがすべて手に入りました!
-/

declare_syntax_cat imp_program
Expand Down Expand Up @@ -203,8 +292,11 @@ partial def elabIMPProgram : Syntax → MetaM Expr
| _ => throwUnsupportedSyntax

/-
--#--
And we can finally test our full elaboration pipeline. Let's use the following
syntax:
--#--
そしてついにエラボレーションのパイプラインを完全にテストすることができます。以下の構文を使ってみましょう:
-/

elab ">>" p:imp_program "<<" : term => elabIMPProgram p
Expand Down
2 changes: 1 addition & 1 deletion md/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
- [構文](./main/05_syntax.md)
- [マクロ](./main/06_macros.md)
- [エラボレーション](./main/07_elaboration.md)
- [Embedding DSLs By Elaboration](./main/08_dsls.md)
- [エラボレーションによる DSL の埋め込み](./main/08_dsls.md)
- [Tactics](./main/09_tactics.md)
- [Lean4 Cheat-sheet](./main/10_cheat-sheet.md)

Expand Down
Loading