これは、この段落の文字通りの解釈の試みである 1 つの可能なアプローチです。
すべての自然数に関する命題を証明するとき、それが に対して成り立つと仮定して、に対しておよび に対してE:N→U
証明すれば十分です。つまり、 および を構成します。0
succ(n)
n
ez:E(0)
es:∏(n:N)E(n)→E(succ(n))
HoTT ブック (セクション 5.1)から。
以下のコードで実装されたものの計画は次のとおりです。
P
「すべての自然数に何らかの性質が成り立つ」という命題の証明を持つとはどういう意味か定式化してください。以下、使用します
trait Forall[N, P[n <: N]]:
inline def apply[n <: N]: P[n]
-メソッドの署名は、apply
本質的に「すべてn <: N
の について、証拠を生成できる」と述べていP[n]
ます。
メソッドが であると宣言されていることに注意してくださいinline
。これは、実行時に証明∀n.P(n)
が建設的で実行可能であることを保証するための 1 つの可能な方法です(ただし、手動で生成された証人用語を使用した別の提案については、編集履歴を参照してください)。
自然数のある種の帰納法を仮定します。以下では、次の定式化を使用します。
If
P(0) holds, and
whenever P(i) holds, then also P(i + 1) holds,
then
For all `n`, P(n) holds
derive
いくつかのメタプログラミング機能を使用して、そのような誘導原理が可能になるはずだと私は信じています。
帰納法の基本の場合と帰納の場合の証明を書いてください。
???
利益
コードは次のようになります。
sealed trait Nat
class O extends Nat
class S[N <: Nat] extends Nat
type plus[a <: Nat, b <: Nat] <: Nat = a match
case O => b
case S[n] => S[n plus b]
trait Forall[N, P[n <: N]]:
inline def apply[n <: N]: P[n]
trait NatInductionPrinciple[P[n <: Nat]] extends Forall[Nat, P]:
def base: P[O]
def step: [i <: Nat] => (P[i] => P[S[i]])
inline def apply[n <: Nat]: P[n] =
(inline compiletime.erasedValue[n] match
case _: O => base
case _: S[pred] => step(apply[pred])
).asInstanceOf[P[n]]
given liftCoUpperbounded[U, A <: U, B <: U, S[_ <: U]](using ev: A =:= B):
(S[A] =:= S[B]) = ev.liftCo[[X] =>> Any].asInstanceOf[S[A] =:= S[B]]
type NatPlusZeroEqualsNat[n <: Nat] = (n plus O) =:= n
def trivialLemma[i <: Nat]: ((S[i] plus O) =:= S[i plus O]) =
summon[(S[i] plus O) =:= S[i plus O]]
object Proof extends NatInductionPrinciple[NatPlusZeroEqualsNat]:
val base = summon[(O plus O) =:= O]
val step: ([i <: Nat] => NatPlusZeroEqualsNat[i] => NatPlusZeroEqualsNat[S[i]]) =
[i <: Nat] => (p: NatPlusZeroEqualsNat[i]) =>
given previousStep: ((i plus O) =:= i) = p
given liftPreviousStep: (S[i plus O] =:= S[i]) =
liftCoUpperbounded[Nat, i plus O, i, S]
given definitionalEquality: ((S[i] plus O) =:= S[i plus O]) =
trivialLemma[i]
definitionalEquality.andThen(liftPreviousStep)
def demoNat(): Unit = {
println("Running demoNat...")
type two = S[S[O]]
val ev = Proof[two]
val twoInstance: two = new S[S[O]]
println(ev(twoInstance) == twoInstance)
}
コンパイル、実行、および出力します。
true
type の実行可能なevidence-termで再帰的に定義されたメソッドの呼び出しに成功したことを意味しますtwo plus O =:= two
。
その他のコメント
- これは、他の s の内部にあるs が誤って再帰ループを生成しない
trivialLemma
ようにするために必要でした。これは少し面倒です。summon
given
- では上限のある型パラメーターを持つ型コンストラクターが許可されないため、別の
liftCo
-method forS[_ <: U]
が必要でした。=:=.liftCo
compiletime.erasedValue
+inline match
すごい!「消去された」型でパターン マッチングを実行できる、ある種のランタイム ギズモを自動的に生成します。これを見つける前に、適切な証人用語を手動で構築しようとしていましたが、これはまったく必要ないようです。無料で提供されています (手動で構築された証人用語によるアプローチについては、編集履歴を参照してください)。