#guard

#guard は与えられた Bool 値が true であることを確かめます。

import Batteries.Data.List.Lemmas -- リストに対して `⊆` が使えるようにする


-- 階乗関数
def fac : Nat → Nat
| 0 => 1
| n + 1 => (n + 1) * fac n

#guard fac 5 == 120

舞台裏

#guardBool ではなく Prop 型の項を与えた場合、エラーになることがあります。次の命題は証明があるので真ですが、 #guard は通りません。

example (α : Type) (l : List α) : [] ⊆ l := by simp

-- Prop 型を持つ
#check ((α : Type) → ∀ (l : List α), [] ⊆ l : Prop)

/--
error: type mismatch
  ∀ (α : Type) (l : List α), [] ⊆ l
has type
  Prop : Type
but is expected to have type
  Bool : Type
---
error: cannot evaluate code because 'sorryAx' uses 'sorry' and/or contains errors
-/
#guard_msgs (whitespace := lax) in
#guard ((α : Type) → ∀ (l : List α), [] ⊆ l : Prop)

しかし、 1 + 1 = 2 等も #check で確かめてみると型は Prop です。にも関わらず #guard に渡してもエラーになりません。これは不思議に思えますが、理由は 1 + 1 = 2Decidable 型クラスのインスタンスであり、決定可能だからです。

-- 型は Prop
/-- info: 1 + 1 = 2 : Prop -/
#guard_msgs in #check 1 + 1 = 2

#guard 1 + 1 = 2

-- 1 + 1 = 2 は決定可能
#synth Decidable (1 + 1 = 2)

Prop 型であっても、Decidable クラスのインスタンスであれば Bool に変換できます。それを自動で行っているので、Prop 型の項でも #guard に通せるというわけです。

-- 決定可能な Prop 型の項を Bool に変換する関数
#check (decide : (p : Prop) → [_h : Decidable p] → Bool)

-- Bool 型になっている
/-- info: decide (1 + 1 = 2) : Bool -/
#guard_msgs in #check decide (1 + 1 = 2)