Skip to content

Commit 4ffaf96

Browse files
authored
Merge pull request #131 from Seasawher/using-check-failure
use `#check_failure` command to erase errors
2 parents 7119967 + 0b92cde commit 4ffaf96

File tree

11 files changed

+151
-92
lines changed

11 files changed

+151
-92
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches:
7+
- master
8+
workflow_dispatch:
9+
10+
jobs:
11+
build:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: checkout
15+
uses: actions/checkout@v4
16+
17+
- name: install elan
18+
run: |
19+
curl https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh -sSf | sh -s -- -y --default-toolchain $(cat lean-toolchain)
20+
echo "$HOME/.elan/bin" >> $GITHUB_PATH
21+
22+
- name: Cache dependencies
23+
uses: actions/cache@v3
24+
with:
25+
path: .lake
26+
key: deps-${{ runner.os }}-${{ hashFiles('lean-toolchain') }}-${{ hashFiles('lake-manifest.json') }}
27+
restore-keys: |
28+
deps-${{ runner.os }}-${{ hashFiles('lean-toolchain') }}
29+
30+
- name: lake build
31+
run: lake build --quiet

lake-manifest.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,19 @@
44
[{"url": "https://github.com/Seasawher/mdgen",
55
"type": "git",
66
"subDir": null,
7-
"rev": "c501f6b8fa2502362bf94678d404857e46e2b65d",
7+
"rev": "2c641fe54d48a5d4adff3a78dbc4a50c5f76b0c0",
88
"name": "mdgen",
99
"manifestFile": "lake-manifest.json",
10-
"inputRev": "c501f6b8fa2502362bf94678d404857e46e2b65d",
10+
"inputRev": "v1.3.0",
11+
"inherited": false,
12+
"configFile": "lakefile.lean"},
13+
{"url": "https://github.com/leanprover/std4",
14+
"type": "git",
15+
"subDir": null,
16+
"rev": "32983874c1b897d78f20d620fe92fc8fd3f06c3a",
17+
"name": "std",
18+
"manifestFile": "lake-manifest.json",
19+
"inputRev": "v4.7.0",
1120
"inherited": false,
1221
"configFile": "lakefile.lean"}],
1322
"name": "«lean4-metaprogramming-book»",

lakefile.lean

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,15 @@ open Lake DSL
44
package «lean4-metaprogramming-book» where
55
srcDir := "lean"
66

7+
@[default_target]
78
lean_lib «lean4-metaprogramming-book» where
89
roots := #[`cover, `extra, `main, `solutions]
910
globs := #[Glob.one `cover, Glob.submodules `extra, Glob.submodules `main, Glob.submodules `solutions]
1011

1112
require mdgen from git
12-
"https://github.com/Seasawher/mdgen" @ "c501f6b8fa2502362bf94678d404857e46e2b65d"
13+
"https://github.com/Seasawher/mdgen" @ "v1.3.0"
14+
15+
require std from git "https://github.com/leanprover/std4" @ "v4.7.0"
1316

1417
def runCmd (cmd : String) (args : Array String) : ScriptM Bool := do
1518
let out ← IO.Process.output {

lean-toolchain

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
leanprover/lean4:v4.4.0
1+
leanprover/lean4:v4.7.0

lean/main/01_intro.lean

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,8 +128,13 @@ elab "#assertType " termStx:term " : " typeStx:term : command =>
128128
logInfo "success"
129129
catch | _ => throwError "failure"
130130

131-
#assertType 5 : Nat -- success
132-
#assertType [] : Nat -- failure
131+
/-- info: success -/
132+
#guard_msgs in --#
133+
#assertType 5 : Nat
134+
135+
/-- error: failure -/
136+
#guard_msgs in --#
137+
#assertType [] : Nat
133138

134139
/-! We started by using `elab` to define a `command` syntax. When parsed
135140
by the compiler, it will trigger the incoming computation.

lean/main/04_metam.lean

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ assigns `?b := f a`. Assigned metavariables are not considered open goals, so
127127
the only goal that remains is `?m3`.
128128
129129
Now the third `apply` comes in. Since `?b` has been assigned, the target of
130-
`?m3` is now `f (f a) = a`. Again, the application of `h` succeeds and the
130+
`?m3` is now `f a = a`. Again, the application of `h` succeeds and the
131131
tactic assigns `?m3 := h a`.
132132
133133
At this point, all metavariables are assigned as follows:
@@ -1235,9 +1235,9 @@ Notice that changing the type of the metavariable from `Nat` to, for example, `S
12351235
-- Instantiate `mvar1`, which should result in expression `2 + ?mvar2 + 1`
12361236
...
12371237
```
1238-
4. [**Metavariables**] Consider the theorem `red`, and tactic `explore` below.
1239-
**a)** What would be the `type` and `userName` of metavariable `mvarId`?
1240-
**b)** What would be the `type`s and `userName`s of all local declarations in this metavariable's local context?
1238+
4. [**Metavariables**] Consider the theorem `red`, and tactic `explore` below.
1239+
**a)** What would be the `type` and `userName` of metavariable `mvarId`?
1240+
**b)** What would be the `type`s and `userName`s of all local declarations in this metavariable's local context?
12411241
Print them all out.
12421242
12431243
```lean
@@ -1256,17 +1256,17 @@ Notice that changing the type of the metavariable from `Nat` to, for example, `S
12561256
sorry
12571257
```
12581258
5. [**Metavariables**] Write a tactic `solve` that proves the theorem `red`.
1259-
6. [**Computation**] What is the normal form of the following expressions:
1260-
**a)** `fun x => x` of type `Bool → Bool`
1261-
**b)** `(fun x => x) ((true && false) || true)` of type `Bool`
1259+
6. [**Computation**] What is the normal form of the following expressions:
1260+
**a)** `fun x => x` of type `Bool → Bool`
1261+
**b)** `(fun x => x) ((true && false) || true)` of type `Bool`
12621262
**c)** `800 + 2` of type `Nat`
12631263
7. [**Computation**] Show that `1` created with `Expr.lit (Lean.Literal.natVal 1)` is definitionally equal to an expression created with `Expr.app (Expr.const ``Nat.succ []) (Expr.const ``Nat.zero [])`.
1264-
8. [**Computation**] Determine whether the following expressions are definitionally equal. If `Lean.Meta.isDefEq` succeeds, and it leads to metavariable assignment, write down the assignments.
1265-
**a)** `5 =?= (fun x => 5) ((fun y : Nat → Nat => y) (fun z : Nat => z))`
1266-
**b)** `2 + 1 =?= 1 + 2`
1267-
**c)** `?a =?= 2`, where `?a` has a type `String`
1268-
**d)** `?a + Int =?= "hi" + ?b`, where `?a` and `?b` don't have a type
1269-
**e)** `2 + ?a =?= 3`
1264+
8. [**Computation**] Determine whether the following expressions are definitionally equal. If `Lean.Meta.isDefEq` succeeds, and it leads to metavariable assignment, write down the assignments.
1265+
**a)** `5 =?= (fun x => 5) ((fun y : Nat → Nat => y) (fun z : Nat => z))`
1266+
**b)** `2 + 1 =?= 1 + 2`
1267+
**c)** `?a =?= 2`, where `?a` has a type `String`
1268+
**d)** `?a + Int =?= "hi" + ?b`, where `?a` and `?b` don't have a type
1269+
**e)** `2 + ?a =?= 3`
12701270
**f)** `2 + ?a =?= 2 + 1`
12711271
9. [**Computation**] Write down what you expect the following code to output.
12721272
@@ -1300,14 +1300,14 @@ Notice that changing the type of the metavariable from `Nat` to, for example, `S
13001300
let reducedExpr ← Meta.reduce constantExpr
13011301
dbg_trace (← ppExpr reducedExpr) -- ...
13021302
```
1303-
10. [**Constructing Expressions**] Create expression `fun x, 1 + x` in two ways:
1304-
**a)** not idiomatically, with loose bound variables
1305-
**b)** idiomatically.
1303+
10. [**Constructing Expressions**] Create expression `fun x, 1 + x` in two ways:
1304+
**a)** not idiomatically, with loose bound variables
1305+
**b)** idiomatically.
13061306
In what version can you use `Lean.mkAppN`? In what version can you use `Lean.Meta.mkAppM`?
13071307
11. [**Constructing Expressions**] Create expression `∀ (yellow: Nat), yellow`.
1308-
12. [**Constructing Expressions**] Create expression `∀ (n : Nat), n = n + 1` in two ways:
1309-
**a)** not idiomatically, with loose bound variables
1310-
**b)** idiomatically.
1308+
12. [**Constructing Expressions**] Create expression `∀ (n : Nat), n = n + 1` in two ways:
1309+
**a)** not idiomatically, with loose bound variables
1310+
**b)** idiomatically.
13111311
In what version can you use `Lean.mkApp3`? In what version can you use `Lean.Meta.mkEq`?
13121312
13. [**Constructing Expressions**] Create expression `fun (f : Nat → Nat), ∀ (n : Nat), f n = f (n + 1)` idiomatically.
13131313
14. [**Constructing Expressions**] What would you expect the output of the following code to be?

lean/main/05_syntax.lean

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,12 @@ We can now write `MyTerm` in place of things like `1 + 1` and it will be
154154
it just means that the Lean parser can understand it:
155155
-/
156156

157-
def Playground1.test := MyTerm
157+
#check_failure MyTerm
158158
-- elaboration function for 'termMyTerm' has not been implemented
159159
-- MyTerm
160160

161+
/-! Note: `#check_failure` command allows incorrectly typed terms to be indicated without error. -/
162+
161163
/-!
162164
Implementing this so-called "elaboration function", which will actually
163165
give meaning to this syntax in terms of Lean's fundamental `Expr` type,
@@ -182,7 +184,7 @@ scoped syntax "⊥" : term -- ⊥ for false
182184
scoped syntax "⊤" : term -- ⊤ for true
183185
scoped syntax:40 term " OR " term : term
184186
scoped syntax:50 term " AND " term : term
185-
#check ⊥ OR (⊤ AND ⊥) -- elaboration function hasn't been implemented but parsing passes
187+
#check_failure ⊥ OR (⊤ AND ⊥) -- elaboration function hasn't been implemented but parsing passes
186188

187189
end Playground2
188190

@@ -203,9 +205,11 @@ syntax:50 boolean_expr " AND " boolean_expr : boolean_expr
203205
Now that we are working in our own syntax category, we are completely
204206
disconnected from the rest of the system. And these cannot be used in place of
205207
terms anymore:
206-
-/
207208
209+
```lean
208210
#check ⊥ AND ⊤ -- expected term
211+
```
212+
-/
209213

210214
/-!
211215
In order to integrate our syntax category into the rest of the system we will
@@ -214,7 +218,7 @@ will re-embed it into the `term` category:
214218
-/
215219

216220
syntax "[Bool|" boolean_expr "]" : term
217-
#check [Bool| ⊥ AND ⊤] -- elaboration function hasn't been implemented but parsing passes
221+
#check_failure [Bool| ⊥ AND ⊤] -- elaboration function hasn't been implemented but parsing passes
218222

219223
/-!
220224
### Syntax combinators
@@ -272,23 +276,25 @@ syntax binNumber := binDigit,+
272276
/-!
273277
Since we can just use named parsers in place of syntax categories, we can now easily
274278
add this to the `term` category:
275-
-/
276279
280+
```lean
277281
syntax "bin(" binNumber ")" : term
278282
#check bin(Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
279283
#check bin() -- fails to parse because `binNumber` is "one or many": expected 'O' or 'Z'
284+
```
285+
-/
280286

281287
syntax binNumber' := binDigit,* -- note the *
282288
syntax "emptyBin(" binNumber' ")" : term
283-
#check emptyBin() -- elaboration function hasn't been implemented but parsing passes
289+
#check_failure emptyBin() -- elaboration function hasn't been implemented but parsing passes
284290

285291
/-!
286292
Note that nothing is limiting us to only using one syntax combinator per parser,
287293
we could also have written all of this inline:
288294
-/
289295

290296
syntax "binCompact(" ("Z" <|> "O"),+ ")" : term
291-
#check binCompact(Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
297+
#check_failure binCompact(Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
292298

293299
/-!
294300
As a final feature, let's add an optional string comment that explains the binary
@@ -297,8 +303,8 @@ literal being declared:
297303

298304
-- The (...)? syntax means that the part in parentheses is optional
299305
syntax "binDoc(" (str ";")? binNumber ")" : term
300-
#check binDoc(Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
301-
#check binDoc("mycomment"; Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
306+
#check_failure binDoc(Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
307+
#check_failure binDoc("mycomment"; Z, O, Z, Z, O) -- elaboration function hasn't been implemented but parsing passes
302308

303309
/-!
304310
## Operating on Syntax
@@ -559,15 +565,15 @@ the bound variables, we refer the reader to the macro chapter.
559565
560566
1. Create an "urgent minus 💀" notation such that `5 * 8 💀 4` returns `20`, and `8 💀 6 💀 1` returns `3`.
561567
562-
**a)** Using `notation` command.
563-
**b)** Using `infix` command.
564-
**c)** Using `syntax` command.
568+
**a)** Using `notation` command.
569+
**b)** Using `infix` command.
570+
**c)** Using `syntax` command.
565571
566572
Hint: multiplication in Lean 4 is defined as `infixl:70 " * " => HMul.hMul`.
567573
568574
2. Consider the following syntax categories: `term`, `command`, `tactic`; and 3 syntax rules given below. Make use of each of these newly defined syntaxes.
569575
570-
```
576+
```lean
571577
syntax "good morning" : term
572578
syntax "hello" : command
573579
syntax "yellow" : tactic

lean/main/06_macros.lean

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ to indicate that "it doesn't feel responsible for this syntax". In this case
3535
it's merely used to fill a wildcard pattern that should never be reached anyways.
3636
3737
However we can in fact register multiple macros for the same syntax this way
38-
if we desire, they will be tried one after another (the later registered ones have
38+
if we desire, they will be tried one after another (the later registered ones have
3939
higher priority) -- is "higher" correct?
4040
until one throws either a real error using `Macro.throwError` or succeeds, that
4141
is it does not `Macro.throwUnsupported`. Let's see this in action:
@@ -169,7 +169,7 @@ for example macro creating macros, we can escape the anti quotation using: `` `(
169169
If we want to specify the syntax kind we wish `x` to be interpreted as
170170
we can make this explicit using: `` `($x:term) `` where `term` can be
171171
replaced with any other valid syntax category (e.g. `command`) or parser
172-
(e.g. `ident`).
172+
(e.g. `ident`).
173173
174174
So far this is only a more formal explanation of the intuitive things
175175
we've already seen in the syntax chapter and up to now in this chapter,
@@ -198,11 +198,11 @@ For example:
198198
-/
199199

200200
-- syntactically cut away the first element of a tuple if possible
201-
syntax "cut_tuple " "(" term ", " term,+ ")" : term
201+
syntax "cut_tuple " "(" term ", " term,+ ")" : term
202202

203203
macro_rules
204204
-- cutting away one element of a pair isn't possible, it would not result in a tuple
205-
| `(cut_tuple ($x, $y)) => `(($x, $y))
205+
| `(cut_tuple ($x, $y)) => `(($x, $y))
206206
| `(cut_tuple ($x, $y, $xs,*)) => `(($y, $xs,*))
207207

208208
#check cut_tuple (1, 2) -- (1, 2) : Nat × Nat
@@ -225,7 +225,7 @@ we know so far we'd have to write two `macro_rules` now, one for the case
225225
with, one for the case without the optional argument. However the rest
226226
of the syntactic translation works exactly the same with and without
227227
the optional argument so what we can do using a splice here is to essentially
228-
define both cases at once:
228+
define both cases at once:
229229
-/
230230

231231
macro_rules
@@ -410,8 +410,8 @@ macro_rules
410410
-- in this case `error_position`, giving it the name `tk`
411411
| `(error_position%$tk first) => withRef tk (Macro.throwError "Ahhh")
412412

413-
#eval error_position all -- the error is indicated at `error_position all`
414-
#eval error_position first -- the error is only indicated at `error_position`
413+
#check_failure error_position all -- the error is indicated at `error_position all`
414+
#check_failure error_position first -- the error is only indicated at `error_position`
415415

416416
/-
417417
Obviously controlling the positions of errors in this way is quite important

lean/main/07_elaboration.lean

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ elab "#findCElab " c:command : command => do
173173
/-!
174174
TODO: Maybe we should also add a mini project that demonstrates a
175175
non # style command aka a declaration, although nothing comes to mind right now.
176-
TODO: Define a `conjecture` declaration, similar to `lemma/theorem`, except that
176+
TODO: Define a `conjecture` declaration, similar to `lemma/theorem`, except that
177177
it is automatically sorried. The `sorry` could be a custom one, to reflect that
178178
the "conjecture" might be expected to be true.
179179
-/
@@ -260,7 +260,7 @@ this information to complete elaboration.
260260
We can also easily provoke cases where this does not work out. For example:
261261
-/
262262

263-
#check set_option trace.Elab.postpone true in List.foldr .add
263+
#check_failure set_option trace.Elab.postpone true in List.foldr .add
264264
-- [Elab.postpone] .add : ?m.5808 → ?m.5809 → ?m.5809
265265
-- invalid dotted identifier notation, expected type is not of the form (... → C ...) where C is a constant
266266
-- ?m.5808 → ?m.5809 → ?m.5809
@@ -316,7 +316,7 @@ def myanonImpl : TermElab := fun stx typ? => do
316316
-- Term elaborators can only postpone execution once, so the elaborator
317317
-- doesn't end up in an infinite loop. Hence, we only try to postpone it,
318318
-- otherwise we may cause an error.
319-
tryPostponeIfNoneOrMVar typ?
319+
tryPostponeIfNoneOrMVar typ?
320320
-- If we haven't found the type after postponing just error
321321
let some typ := typ? | throwError "expected type must be known"
322322
if typ.isMVar then
@@ -328,17 +328,17 @@ def myanonImpl : TermElab := fun stx typ? => do
328328
elabTerm stx typ -- call term elaboration recursively
329329

330330
#check (⟨⟨1, sorry⟩⟩ : Fin 12) -- { val := 1, isLt := (_ : 1 < 12) } : Fin 12
331-
#check ⟨⟨1, sorry⟩⟩ -- expected type must be known
332-
#check (⟨⟨0⟩⟩ : Nat) -- type doesn't have exactly one constructor
333-
#check (⟨⟨⟩⟩ : Nat → Nat) -- type is not of the expected form: Nat -> Nat
331+
#check_failure ⟨⟨1, sorry⟩⟩ -- expected type must be known
332+
#check_failure (⟨⟨0⟩⟩ : Nat) -- type doesn't have exactly one constructor
333+
#check_failure (⟨⟨⟩⟩ : Nat → Nat) -- type is not of the expected form: Nat -> Nat
334334

335335
/-!
336336
As a final note, we can shorten the postponing act by using an additional
337337
syntax sugar of the `elab` syntax instead:
338338
-/
339339

340340
-- This `t` syntax will effectively perform the first two lines of `myanonImpl`
341-
elab "⟨⟨" args:term,* "⟩⟩" : term <= t => do
341+
elab "⟨⟨" args:term,* "⟩⟩" : term <= t => do
342342
sorry
343343

344344

@@ -377,8 +377,8 @@ elab "⟨⟨" args:term,* "⟩⟩" : term <= t => do
377377
378378
Please add these semantics:
379379
380-
**a)** using `syntax` + `@[command_elab alias] def elabOurAlias : CommandElab`.
381-
**b)** using `syntax` + `elab_rules`.
380+
**a)** using `syntax` + `@[command_elab alias] def elabOurAlias : CommandElab`.
381+
**b)** using `syntax` + `elab_rules`.
382382
**c)** using `elab`.
383383
384384
3. Here is some syntax taken from a real mathlib tactic `nth_rewrite`.
@@ -392,8 +392,8 @@ elab "⟨⟨" args:term,* "⟩⟩" : term <= t => do
392392
393393
Please add these semantics:
394394
395-
**a)** using `syntax` + `@[tactic nthRewrite] def elabNthRewrite : Lean.Elab.Tactic.Tactic`.
396-
**b)** using `syntax` + `elab_rules`.
395+
**a)** using `syntax` + `@[tactic nthRewrite] def elabNthRewrite : Lean.Elab.Tactic.Tactic`.
396+
**b)** using `syntax` + `elab_rules`.
397397
**c)** using `elab`.
398398
399399
-/

0 commit comments

Comments
 (0)