Skip to content

Commit 6f1cc3b

Browse files
digama0kim-em
andcommitted
feat: ring_exp tactic, subtraction in ring (#519)
Another complete rewrite. This implements one `ring` to rule them all: it incorporates both `ring_exp` and `ring` behaviors, now under the name `ring`. (`ring_exp` had some small (1.4x) performance issues that prevented it from being used by default; I'm hoping that those issues are fixed now, and we can revisit later if it becomes an issue.) Co-authored-by: Scott Morrison <scott.morrison@gmail.com>
1 parent 0c6ca88 commit 6f1cc3b

File tree

9 files changed

+1124
-456
lines changed

9 files changed

+1124
-456
lines changed

Mathlib/Algebra/GroupPower/Basic.lean

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ theorem add_nsmul (a : M) (m n : ℕ) : (m + n) • a = m • a + n • a := by
2727
| zero => rw [Nat.zero_add, zero_nsmul, zero_add]
2828
| succ m ih => rw [Nat.succ_add, Nat.succ_eq_add_one, succ_nsmul, ih, succ_nsmul, add_assoc]
2929

30+
theorem succ_nsmul' (a : M) (n : ℕ) : (n + 1) • a = n • a + a := by
31+
rw [add_nsmul, one_nsmul]
32+
3033
end AddMonoid
3134

3235
section Monoid
@@ -57,6 +60,8 @@ theorem Commute.mul_pow {a b : M} (h : Commute a b) (n : ℕ) : (a * b) ^ n = a
5760
· rw [pow_zero, pow_zero, pow_zero, one_mul]
5861
· simp only [pow_succ, ih, ← mul_assoc, (h.pow_left n).right_comm]
5962

63+
attribute [to_additive succ_nsmul'] pow_succ'
64+
6065
end Monoid
6166

6267
/-!

Mathlib/Algebra/GroupPower/Lemmas.lean

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
44
Authors: Jeremy Avigad, Robert Y. Lewis
55
-/
66
import Mathlib.Data.Int.Cast
7+
import Mathlib.Algebra.GroupPower.Basic
78

89
/-!
910
# Lemmas about power operations on monoids and groups
@@ -18,3 +19,11 @@ theorem Int.cast_pow [Ring R] (n : ℤ) : ∀ m : ℕ, (↑(n ^ m) : R) = (n : R
1819
| n+1 => by rw [pow_succ, pow_succ, Int.cast_mul, Int.cast_pow _ n]
1920

2021
@[simp] theorem pow_eq {m : ℤ} {n : ℕ} : m.pow n = m ^ n := rfl
22+
23+
theorem nsmul_eq_mul' [Semiring R] (a : R) (n : ℕ) : n • a = a * n := by
24+
induction' n with n ih
25+
· rw [zero_nsmul, Nat.cast_zero, mul_zero]
26+
· rw [succ_nsmul', ih, Nat.cast_succ, mul_add, mul_one]
27+
28+
@[simp] theorem nsmul_eq_mul [Semiring R] (n : ℕ) (a : R) : n • a = n * a := by
29+
rw [nsmul_eq_mul', (n.cast_commute a).eq]

Mathlib/Algebra/Ring/Basic.lean

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,21 @@ class Semiring (R : Type u) extends NonUnitalSemiring R, NonAssocSemiring R, Mon
3434

3535
section Semiring
3636

37+
-- TODO: put these in the right place
38+
@[simp] theorem Commute.zero_right [Semiring R] (a : R) : Commute a 0 :=
39+
(mul_zero _).trans (zero_mul _).symm
40+
41+
@[simp] theorem Commute.zero_left [Semiring R] (a : R) : Commute 0 a :=
42+
(zero_mul _).trans (mul_zero _).symm
43+
44+
@[simp] theorem Commute.add_right [Semiring R] {a b c : R} (h : Commute a b) (h' : Commute a c) :
45+
Commute a (b + c) := by
46+
simp only [Commute, SemiconjBy, left_distrib, right_distrib, h.eq, h'.eq]
47+
48+
@[simp] theorem Commute.add_left [Semiring R] {a b c : R} (h : Commute a c) (h' : Commute b c) :
49+
Commute (a + b) c := by
50+
simp only [Commute, SemiconjBy, left_distrib, right_distrib, h.eq, h'.eq]
51+
3752
@[simp]
3853
lemma Nat.cast_mul [Semiring R] {m n : ℕ} : (m * n).cast = (m.cast * n.cast : R) := by
3954
induction n generalizing m <;> simp_all [mul_succ, mul_add]
@@ -42,6 +57,11 @@ lemma Nat.cast_mul [Semiring R] {m n : ℕ} : (m * n).cast = (m.cast * n.cast :
4257
lemma Nat.cast_pow [Semiring R] {m n : ℕ} : (m ^ n).cast = (m.cast ^ n : R) := by
4358
induction n generalizing m <;> simp_all [Nat.pow_succ', _root_.pow_succ'', pow_zero]
4459

60+
theorem Nat.cast_commute [Semiring α] (n : ℕ) (x : α) : Commute (↑n) x := by
61+
induction n with
62+
| zero => rw [Nat.cast_zero]; exact Commute.zero_left x
63+
| succ n ihn => rw [Nat.cast_succ] <;> exact ihn.add_left (Commute.one_left x)
64+
4565
end Semiring
4666

4767
class CommSemiring (R : Type u) extends Semiring R, CommMonoid R where
@@ -52,10 +72,13 @@ class Ring (R : Type u) extends Semiring R, AddCommGroup R, AddGroupWithOne R
5272

5373
example [Ring R] : HasInvolutiveNeg R := inferInstance
5474

55-
theorem neg_mul_eq_neg_mul {R} [Ring R] (a b : R) : -(a * b) = (-a) * b :=
56-
Eq.symm <| eq_of_sub_eq_zero' <| by
57-
rw [sub_eq_add_neg, neg_neg (a * b) /- TODO: why is arg necessary? -/]
58-
rw [← add_mul, neg_add_self a /- TODO: why is arg necessary? -/, zero_mul]
75+
@[simp] theorem neg_mul {R} [Ring R] (a b : R) : (-a) * b = -(a * b) :=
76+
eq_of_sub_eq_zero' <| by rw [sub_eq_add_neg, neg_neg, ← add_mul, neg_add_self, zero_mul]
77+
78+
@[simp] lemma mul_neg [Ring R] (a b : R) : a * -b = - (a * b) :=
79+
eq_of_sub_eq_zero' <| by rw [sub_eq_add_neg, neg_neg, ← mul_add, neg_add_self, mul_zero]
80+
81+
theorem neg_mul_eq_neg_mul {R} [Ring R] (a b : R) : -(a * b) = (-a) * b := (neg_mul ..).symm
5982

6083
theorem mul_sub_right_distrib [Ring R] (a b c : R) : (a - b) * c = a * c - b * c := by
6184
simpa only [sub_eq_add_neg, neg_mul_eq_neg_mul] using add_mul a (-b) c

Mathlib/Mathport/Syntax.lean

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -332,18 +332,9 @@ syntax termList := " [" term,* "]"
332332
/- B -/ syntax (name := abel) "abel" (ppSpace (&"raw" <|> &"term"))? (ppSpace location)? : tactic
333333
/- B -/ syntax (name := abel!) "abel!" (ppSpace (&"raw" <|> &"term"))? (ppSpace location)? : tactic
334334

335-
/- E -/ syntax (name := ring1) "ring1" : tactic
336-
/- E -/ syntax (name := ring1!) "ring1!" : tactic
337-
338335
syntax ringMode := &"SOP" <|> &"raw" <|> &"horner"
339336
/- E -/ syntax (name := ringNF) "ring_nf" (ppSpace ringMode)? (ppSpace location)? : tactic
340337
/- E -/ syntax (name := ringNF!) "ring_nf!" (ppSpace ringMode)? (ppSpace location)? : tactic
341-
/- E -/ syntax (name := ring!) "ring!" : tactic
342-
343-
/- B -/ syntax (name := ringExpEq) "ring_exp_eq" : tactic
344-
/- B -/ syntax (name := ringExpEq!) "ring_exp_eq!" : tactic
345-
/- B -/ syntax (name := ringExp) "ring_exp" (ppSpace location)? : tactic
346-
/- B -/ syntax (name := ringExp!) "ring_exp!" (ppSpace location)? : tactic
347338

348339
/- E -/ syntax (name := noncommRing) "noncomm_ring" : tactic
349340

Mathlib/Tactic/NormNum/Basic.lean

Lines changed: 67 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -109,28 +109,41 @@ theorem isInt_add {α} [Ring α] : {a b : α} → {a' b' c : ℤ} →
109109
IsInt a a' → IsInt b b' → Int.add a' b' = c → IsInt (a + b) c
110110
| _, _, _, _, _, ⟨rfl⟩, ⟨rfl⟩, rfl => ⟨(Int.cast_add ..).symm⟩
111111

112+
instance : MonadLift Option MetaM where
113+
monadLift
114+
| none => failure
115+
| some e => pure e
116+
112117
/-- The `norm_num` extension which identifies expressions of the form `a + b`,
113118
such that `norm_num` successfully recognises both `a` and `b`. -/
114119
@[norm_num _ + _, Add.add _ _] def evalAdd : NormNumExt where eval {u α} e := do
115120
let .app (.app f (a : Q($α))) (b : Q($α)) ← withReducible (whnf e) | failure
116121
let ra ← derive a; let rb ← derive b
117-
let intArm (rα : Q(Ring $α)) := do
118-
let ⟨za, na, pa⟩ ← ra.toInt; let ⟨zb, nb, pb⟩ ← rb.toInt
119-
let zc := za + zb
120-
have c := mkRawIntLit zc
121-
let r : Q(Int.add $na $nb = $c) := (q(Eq.refl $c) : Expr)
122-
return (.isInt rα zc q(isInt_add $pa $pb $r) : Result q($a + $b))
123122
match ra, rb with
124-
| .isNat _ na pa, .isNat sα nb pb =>
125-
have pa : Q(IsNat $a $na) := pa
123+
| .isNat _ .., .isNat _ .. | .isNat _ .., .isNegNat _ ..
124+
| .isNegNat _ .., .isNat _ .. | .isNegNat _ .., .isNegNat _ .. =>
126125
guard <|← withNewMCtxDepth <| isDefEq f q(HAdd.hAdd (α := $α))
127-
have c : Q(ℕ) := mkRawNatLit (na.natLit! + nb.natLit!)
128-
let r : Q(Nat.add $na $nb = $c) := (q(Eq.refl $c) : Expr)
129-
return (.isNat sα c q(isNat_add $pa $pb $r) : Result q($a + $b))
130-
| .isNat _ .., .isNegNat rα ..
131-
| .isNegNat rα .., .isNat _ ..
132-
| .isNegNat _ .., .isNegNat rα .. => intArm rα
133126
| _, _ => failure
127+
let rec
128+
/-- Main part of `evalAdd`. -/
129+
core : Option (Result e) := do
130+
let intArm (rα : Q(Ring $α)) := do
131+
let ⟨za, na, pa⟩ ← ra.toInt; let ⟨zb, nb, pb⟩ ← rb.toInt
132+
let zc := za + zb
133+
have c := mkRawIntLit zc
134+
let r : Q(Int.add $na $nb = $c) := (q(Eq.refl $c) : Expr)
135+
return (.isInt rα zc q(isInt_add $pa $pb $r) : Result q($a + $b))
136+
match ra, rb with
137+
| .isNat _ na pa, .isNat sα nb pb =>
138+
have pa : Q(IsNat $a $na) := pa
139+
have c : Q(ℕ) := mkRawNatLit (na.natLit! + nb.natLit!)
140+
let r : Q(Nat.add $na $nb = $c) := (q(Eq.refl $c) : Expr)
141+
return (.isNat sα c q(isNat_add $pa $pb $r) : Result q($a + $b))
142+
| .isNat _ .., .isNegNat rα ..
143+
| .isNegNat rα .., .isNat _ ..
144+
| .isNegNat _ .., .isNegNat rα .. => intArm rα
145+
| _, _ => failure
146+
core
134147

135148
theorem isInt_neg {α} [Ring α] : {a : α} → {a' b : ℤ} →
136149
IsInt a a' → Int.neg a' = b → IsInt (-a) b
@@ -177,24 +190,31 @@ such that `norm_num` successfully recognises both `a` and `b`. -/
177190
@[norm_num _ * _, Mul.mul _ _] def evalMul : NormNumExt where eval {u α} e := do
178191
let .app (.app f (a : Q($α))) (b : Q($α)) ← withReducible (whnf e) | failure
179192
let ra ← derive a; let rb ← derive b
180-
let intArm (rα : Q(Ring $α)) := do
181-
guard <|← withNewMCtxDepth <| isDefEq f q(HMul.hMul (α := $α))
182-
let ⟨za, na, pa⟩ ← ra.toInt; let ⟨zb, nb, pb⟩ ← rb.toInt
183-
let zc := za * zb
184-
have c := mkRawIntLit zc
185-
let r : Q(Int.mul $na $nb = $c) := (q(Eq.refl $c) : Expr)
186-
return (.isInt rα zc q(isInt_mul $pa $pb $r) : Result q($a * $b))
187193
match ra, rb with
188-
| .isNat _ na pa, .isNat sα nb pb =>
189-
have pa : Q(IsNat $a $na) := pa
194+
| .isNat _ .., .isNat _ .. | .isNat _ .., .isNegNat _ ..
195+
| .isNegNat _ .., .isNat _ .. | .isNegNat _ .., .isNegNat _ .. =>
190196
guard <|← withNewMCtxDepth <| isDefEq f q(HMul.hMul (α := $α))
191-
have c : Q(ℕ) := mkRawNatLit (na.natLit! * nb.natLit!)
192-
let r : Q(Nat.mul $na $nb = $c) := (q(Eq.refl $c) : Expr)
193-
return (.isNat sα c q(isNat_mul $pa $pb $r) : Result q($a * $b))
194-
| .isNat _ .., .isNegNat rα ..
195-
| .isNegNat rα .., .isNat _ ..
196-
| .isNegNat _ .., .isNegNat rα .. => intArm rα
197197
| _, _ => failure
198+
let rec
199+
/-- Main part of `evalMul`. -/
200+
core : Option (Result e) := do
201+
let intArm (rα : Q(Ring $α)) := do
202+
let ⟨za, na, pa⟩ ← ra.toInt; let ⟨zb, nb, pb⟩ ← rb.toInt
203+
let zc := za * zb
204+
have c := mkRawIntLit zc
205+
let r : Q(Int.mul $na $nb = $c) := (q(Eq.refl $c) : Expr)
206+
return (.isInt rα zc q(isInt_mul $pa $pb $r) : Result q($a * $b))
207+
match ra, rb with
208+
| .isNat _ na pa, .isNat sα nb pb =>
209+
have pa : Q(IsNat $a $na) := pa
210+
have c : Q(ℕ) := mkRawNatLit (na.natLit! * nb.natLit!)
211+
let r : Q(Nat.mul $na $nb = $c) := (q(Eq.refl $c) : Expr)
212+
return (.isNat sα c q(isNat_mul $pa $pb $r) : Result q($a * $b))
213+
| .isNat _ .., .isNegNat rα ..
214+
| .isNegNat rα .., .isNat _ ..
215+
| .isNegNat _ .., .isNegNat rα .. => intArm rα
216+
| _, _ => failure
217+
core
198218

199219
theorem isNat_pow {α} [Semiring α] : {a : α} → {b a' b' c : ℕ} →
200220
IsNat a a' → IsNat b b' → Nat.pow a' b' = c → IsNat (a ^ b) c
@@ -212,17 +232,23 @@ def evalPow : NormNumExt where eval {u α} e := do
212232
let ⟨nb, pb⟩ ← deriveNat b q(instSemiringNat)
213233
let ra ← derive a
214234
match ra with
215-
| .isNat sα na pa =>
235+
| .isNat _ .. | .isNegNat _ .. =>
216236
guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(HPow.hPow (α := $α))
217-
have c : Q(ℕ) := mkRawNatLit (na.natLit! ^ nb.natLit!)
218-
let r : Q(Nat.pow $na $nb = $c) := (q(Eq.refl $c) : Expr)
219-
let pb : Q(IsNat $b $nb) := pb
220-
return (.isNat sα c q(isNat_pow $pa $pb $r) : Result q($a ^ $b))
221-
| .isNegNat rα .. =>
222-
guard <|← withDefault <| withNewMCtxDepth <| isDefEq f q(HPow.hPow (α := $α))
223-
let ⟨za, na, pa⟩ ← ra.toInt
224-
let zc := za ^ nb.natLit!
225-
let c := mkRawIntLit zc
226-
let r : Q(Int.pow $na $nb = $c) := (q(Eq.refl $c) : Expr)
227-
return (.isInt rα zc (z := c) q(isInt_pow $pa $pb $r) : Result q($a ^ $b))
228237
| _ => failure
238+
let rec
239+
/-- Main part of `evalPow`. -/
240+
core : Option (Result e) := do
241+
match ra with
242+
| .isNat sα na pa =>
243+
have c : Q(ℕ) := mkRawNatLit (na.natLit! ^ nb.natLit!)
244+
let r : Q(Nat.pow $na $nb = $c) := (q(Eq.refl $c) : Expr)
245+
let pb : Q(IsNat $b $nb) := pb
246+
return (.isNat sα c q(isNat_pow $pa $pb $r) : Result q($a ^ $b))
247+
| .isNegNat rα .. =>
248+
let ⟨za, na, pa⟩ ← ra.toInt
249+
let zc := za ^ nb.natLit!
250+
let c := mkRawIntLit zc
251+
let r : Q(Int.pow $na $nb = $c) := (q(Eq.refl $c) : Expr)
252+
return (.isInt rα zc (z := c) q(isInt_pow $pa $pb $r) : Result q($a ^ $b))
253+
| _ => failure
254+
core

Mathlib/Tactic/NormNum/Core.lean

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,13 @@ structure IsNat [Semiring α] (a : α) (n : ℕ) : Prop where
3434

3535
theorem IsNat.raw_refl (n : ℕ) : IsNat n n := ⟨rfl⟩
3636

37+
/--
38+
A "raw nat cast" is an expression of the form `(Nat.rawCast lit : α)` where `lit` is a raw
39+
natural number literal. These expressions are used by tactics like `ring` to decrease the number
40+
of typeclass arguments required in each use of a number literal at type `α`.
41+
-/
42+
@[simp] def _root_.Nat.rawCast [Semiring α] (n : ℕ) : α := n
43+
3744
/-- Asserting that the `OfNat α n` instance provides the same value as the coercion. -/
3845
class LawfulOfNat (α) [Semiring α] (n) [OfNat α n] : Prop where
3946
/-- Assert `n = (OfNat.ofNat n α)`, with the parametrising instance. -/
@@ -45,21 +52,43 @@ instance (α) [Semiring α] : LawfulOfNat α (nat_lit 1) := ⟨Nat.cast_one⟩
4552
instance : LawfulOfNat ℕ n := ⟨show n = Nat.cast n by simp⟩
4653
instance : LawfulOfNat ℤ n := ⟨show Int.ofNat n = Nat.cast n by simp⟩
4754

48-
theorem IsNat.to_eq {α} [Semiring α] (n) [OfNat α n] [LawfulOfNat α n] :
55+
theorem IsNat.to_eq [Semiring α] (n) [OfNat α n] [LawfulOfNat α n] :
4956
(a : α) → IsNat a n → a = OfNat.ofNat n
5057
| _, ⟨rfl⟩ => LawfulOfNat.eq_ofNat
5158

59+
theorem IsNat.to_raw_eq [Semiring α] : IsNat (a : α) n → a = n.rawCast
60+
| ⟨e⟩ => e
61+
62+
theorem IsNat.of_raw (α) [Semiring α] (n : ℕ) : IsNat (n.rawCast : α) n := ⟨rfl⟩
63+
5264
/-- Assert that an element of a ring is equal to the coercion of some integer. -/
5365
structure IsInt [Ring α] (a : α) (n : ℤ) : Prop where
5466
/-- The element is equal to the coercion of the integer. -/
5567
out : a = n
5668

69+
/--
70+
A "raw int cast" is an expression of the form:
71+
72+
* `(Nat.rawCast lit : α)` where `lit` is a raw natural number literal
73+
* `(Int.rawCast (Int.negOfNat lit) : α)` where `lit` is a nonzero raw natural number literal
74+
75+
(That is, we only actually use this function for negative integers.) This representation is used by
76+
tactics like `ring` to decrease the number of typeclass arguments required in each use of a number
77+
literal at type `α`.
78+
-/
79+
@[simp] def _root_.Int.rawCast [Ring α] (n : ℤ) : α := n
80+
5781
theorem IsInt.to_isNat {α} [Ring α] : ∀ {a : α} {n}, IsInt a (.ofNat n) → IsNat a n
5882
| _, _, ⟨rfl⟩ => ⟨by simp⟩
5983

6084
theorem IsNat.to_isInt {α} [Ring α] : ∀ {a : α} {n}, IsNat a n → IsInt a (.ofNat n)
6185
| _, _, ⟨rfl⟩ => ⟨by simp⟩
6286

87+
theorem IsInt.to_raw_eq [Ring α] : IsInt (a : α) n → a = n.rawCast
88+
| ⟨e⟩ => e
89+
90+
theorem IsInt.of_raw (α) [Ring α] (n : ℤ) : IsInt (n.rawCast : α) n := ⟨rfl⟩
91+
6392
theorem IsInt.neg_to_eq {α} [Ring α] (n) [OfNat α n] [LawfulOfNat α n] :
6493
(a : α) → IsInt a (.negOfNat n) → a = -OfNat.ofNat n
6594
| _, ⟨rfl⟩ => by simp [Int.negOfNat_eq, Int.cast_neg]; apply LawfulOfNat.eq_ofNat
@@ -113,13 +142,16 @@ inductive Result' where
113142
| isNegNat (inst lit proof : Expr)
114143
/-- Untyped version of `Result.isRat`. -/
115144
| isRat (inst : Expr) (q : Rat) (n d proof : Expr)
145+
deriving Inhabited
116146

117147
section
118148
set_option linter.unusedVariables false
119149

120150
/-- The result of `norm_num` running on an expression `x` of type `α`. -/
121151
@[nolint unusedArguments] def Result {α : Q(Type u)} (x : Q($α)) := Result'
122152

153+
instance : Inhabited (Result x) := inferInstanceAs (Inhabited Result')
154+
123155
/-- The result is `lit : ℕ` (a raw nat literal) and `proof : isNat x lit`. -/
124156
@[match_pattern, inline] def Result.isNat {α : Q(Type u)} {x : Q($α)} :
125157
∀ (inst : Q(Semiring $α) := by assumption) (lit : Q(ℕ)) (proof : Q(IsNat $x $lit)),
@@ -165,7 +197,7 @@ Extract from a `Result` the integer value (as both a term and an expression),
165197
and the proof that the original expression is equal to this integer.
166198
-/
167199
def Result.toInt {α : Q(Type u)} {e : Q($α)} (_i : Q(Ring $α) := by with_reducible assumption) :
168-
Result e → MetaM (ℤ × (lit : Q(ℤ)) × Q(IsInt $e $lit))
200+
Result e → Option (ℤ × (lit : Q(ℤ)) × Q(IsInt $e $lit))
169201
| .isNat _ lit proof => do
170202
have proof : Q(@IsNat _ Ring.toSemiring $e $lit) := proof
171203
pure ⟨lit.natLit!, q(.ofNat $lit), q(($proof).to_isInt)⟩
@@ -178,17 +210,39 @@ instance : ToMessageData (Result x) where
178210
| .isNegNat _ lit proof => m!"isNegNat {lit} ({proof})"
179211
| .isRat _ q _ _ proof => m!"isRat {q} ({proof})"
180212

213+
/--
214+
Given a `NormNum.Result e` (which uses `IsNat` or `IsInt` to express equality to an integer
215+
numeral), converts it to an equality `e = Nat.rawCast n` or `e = Int.rawCast n` to a raw cast
216+
expression, so it can be used for rewriting.
217+
-/
218+
def Result.toRawEq {α : Q(Type u)} {e : Q($α)} : Result e → (ℤ × (e' : Q($α)) × Q($e = $e'))
219+
| .isNat _ lit p => ⟨lit.natLit!, q(Nat.rawCast $lit), q(IsNat.to_raw_eq $p)⟩
220+
| .isNegNat _ lit p => ⟨-lit.natLit!, q(Int.rawCast (.negOfNat $lit)), q(IsInt.to_raw_eq $p)⟩
221+
| .isRat _ .. => ⟨0, (default : Expr), (default : Expr)⟩ -- TODO
222+
223+
/-- Constructs a `Result` out of a raw nat cast. Assumes `e` is a raw nat cast expression. -/
224+
def Result.ofRawNat {α : Q(Type u)} (e : Q($α)) : Result e := Id.run do
225+
let .app (.app _ (sα : Q(Semiring $α))) (lit : Q(ℕ)) := e | panic! "not a raw nat cast"
226+
.isNat sα lit (q(IsNat.of_raw $α $lit) : Expr)
227+
228+
/-- Constructs a `Result` out of a raw int cast.
229+
Assumes `e` is a raw int cast expression denoting `n`. -/
230+
def Result.ofRawInt {α : Q(Type u)} (n : ℤ) (e : Q($α)) : Result e :=
231+
if 0 ≤ n then
232+
Result.ofRawNat e
233+
else Id.run do
234+
let .app (.app _ (rα : Q(Ring $α))) (.app _ (lit : Q(ℕ))) := e | panic! "not a raw int cast"
235+
.isNegNat rα lit (q(IsInt.of_raw $α (.negOfNat $lit)) : Expr)
236+
181237
/--
182238
Convert a `Result` to a `Simp.Result`.
183239
-/
184240
def Result.toSimpResult {α : Q(Type u)} {e : Q($α)} : Result e → MetaM Simp.Result
185241
| .isNat _sα lit p => do
186-
let p : Q(IsNat $e $lit) := p
187242
let _ofNatInst ← synthInstanceQ (q(OfNat $α $lit) : Q(Type u))
188243
let _lawfulInst ← synthInstanceQ (q(LawfulOfNat $α $lit) : Q(Prop))
189244
return { expr := q((OfNat.ofNat $lit : $α)), proof? := q(IsNat.to_eq $lit $e $p) }
190245
| .isNegNat _rα lit p => do
191-
let p : Q(IsInt $e (.negOfNat $lit)) := p
192246
let _ofNatInst ← synthInstanceQ (q(OfNat $α $lit) : Q(Type u))
193247
let _lawfulInst ← synthInstanceQ (q(LawfulOfNat $α $lit) : Q(Prop))
194248
return { expr := q(-(OfNat.ofNat $lit : $α)), proof? := q(IsInt.neg_to_eq $lit $e $p) }
@@ -267,7 +321,7 @@ returning a typed expression `lit : ℤ`, and a proof of `isInt e lit`. -/
267321
def deriveInt {α : Q(Type u)} (e : Q($α))
268322
(_inst : Q(Ring $α) := by with_reducible assumption) :
269323
MetaM ((lit : Q(ℤ)) × Q(IsInt $e $lit)) := do
270-
let ⟨_, lit, proof⟩ (← derive e).toInt
324+
let some ⟨_, lit, proof⟩ := (← derive e).toInt | failure
271325
pure ⟨lit, proof⟩
272326

273327
/-- Extract the natural number `n` if the expression is of the form `OfNat.ofNat n`. -/

0 commit comments

Comments
 (0)