norm_cast
norm_cast は、型キャスト(ある型からある型への変換)を簡約するタクティクです。
詳細については論文 「Simplifying Casts and Coercions」 などを参照してください。
import Mathlib.Tactic
-- `x, m, n` は自然数とする
variable (x m n : ℕ)
example (left : (x : ℝ) < ↑m + ↑n) (right : ↑m + ↑n < (x : ℝ) + 1) : False := by
-- `linarith` では示すことができない
fail_if_success linarith
-- `omega` でも示すことができない
fail_if_success omega
-- 仮定の `left` と `right` は実数上の不等式だが、
-- 自然数上の不等式と解釈できるはずである。
-- `norm_cast` はそれを実行してくれる。
norm_cast at left right
-- 仮定が自然数における不等式に変わった!
guard_hyp left : x < m + n
guard_hyp right : m + n < x + 1
-- 後は `omega` で示せる
omega
[norm_cast] 属性によるカスタマイズ
命題に [norm_cast] 属性を付与することにより、norm_cast タクティクでできることを増やすことができます。
/-- 自然数のペア -/
def IntBase := Nat × Nat
/-- 自然数のペアが「整数として等しい」という同値関係 -/
def IntBase.equiv : IntBase → IntBase → Prop :=
fun (a₁, b₁) (a₂, b₂) => a₁ + b₂ = b₁ + a₂
/-- `IntBase` と同値関係 `IntBase.equiv` をペアにする -/
@[instance] def IntBase.sequiv : Setoid IntBase where
r := IntBase.equiv
iseqv := by
constructor
case refl =>
intro ⟨x, y⟩
dsimp [IntBase.equiv]
ac_rfl
case symm =>
intro ⟨x, y⟩ ⟨x', y'⟩ h
dsimp [IntBase.equiv] at *
omega
case trans =>
intro ⟨x, y⟩ ⟨x', y'⟩ ⟨x'', y''⟩ hxy hyz
dsimp [IntBase.equiv] at *
omega
/-- 自前で定義した整数 -/
abbrev MyInt := Quotient IntBase.sequiv
/-- 自然数を `myInt` と解釈する関数 -/
def MyInt.ofNat (n : Nat) : MyInt := ⟦(n, 0)⟧
@[grind inj]
theorem MyInt.ofNat_inj : Function.Injective MyInt.ofNat := by
intro n m h
dsimp [MyInt.ofNat] at h
have h' : IntBase.equiv (n, 0) (m, 0) := by
apply Quotient.exact h
suffices IntBase.equiv (n, 0) (m, 0) from by
grind [= IntBase.equiv]
assumption
/-- 型強制を定義 -/
instance : Coe Nat MyInt where
coe := MyInt.ofNat
/-- 型キャストの簡約を行う補題。`ℕ` の項が `myInt` として等しいなら、元から等しい。 -/
theorem MyInt_eq {x y : ℕ} : (x : MyInt) = (y : MyInt) ↔ x = y := by
grind
-- `[norm_cast]` 属性の制約として、
-- 登録する補題の中には型強制が含まれていなくてはいけない
-- たとえば `↑` など
/-
error: Invalid `norm_cast` lemma: At least one coe function must appear in the left-hand side
MyInt.ofNat x = MyInt.ofNat y
Note: coe functions are registered using the `[coe]` attribute
-/
attribute [norm_cast] MyInt_eq
-- `[coe]` 属性を付与し、`MyInt.ofNat` を型キャストを行う関数として認識させる
attribute [coe] MyInt.ofNat
example {x y z : ℕ} (h : (x : MyInt) = (y : MyInt)) : x + z = y + z := by
norm_cast at h
-- `norm_cast` の効果が出ていない
guard_hyp h : (x : MyInt) = (y : MyInt)
simp [MyInt_eq] at h
omega
-- `norm_cast` に使ってもらえるように登録する
attribute [norm_cast] MyInt_eq
example {x y z : Nat} (h : (x : MyInt) = (y : MyInt)) : x + z = y + z := by
norm_cast at h
-- `norm_cast` で簡約できるようになった!
guard_hyp h : x = y
omega