Mager , 66 Bytes
def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0
Probieren Sie es online!
Beweis der Richtigkeit
Probieren Sie es online!
Erläuterung
Lassen Sie uns die Funktion entgolfen:
def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0 0 := 1
| _ _ := 0
Die Funktion wird durch Mustervergleich und Rekursion definiert, die beide eine integrierte Unterstützung haben.
Wir definieren s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)
und s(0, 0) = 1
, was offen lässt s(m+1, 0)
und was s(0, n+1)
beide als 0
der letzte Fall definiert sind.
Lean verwendet, so wie es s m n
ist, die Lamdba-Kalkülsyntax s(m, n)
.
Nun zum Beweis der Richtigkeit: Ich habe es auf zwei Arten ausgedrückt:
def correctness : ∀ m n, fin (s m n) ≃ { f : fin m → fin n // function.surjective f } :=
λ m, nat.rec_on m (λ n, nat.cases_on n s_zero_zero (λ n, s_zero_succ n)) $
λ m ih n, nat.cases_on n (s_succ_zero m) $ λ n,
calc fin (s (nat.succ m) (nat.succ n))
≃ (fin (n + 1) × (fin (s m n + s m (n + 1)))) :
(fin_prod _ _).symm
... ≃ (fin (n + 1) × (fin (s m n) ⊕ fin (s m (n + 1)))) :
equiv.prod_congr (equiv.refl _) (fin_sum _ _).symm
... ≃ (fin (n + 1) × ({f : fin m → fin n // function.surjective f} ⊕
{f : fin m → fin (n + 1) // function.surjective f})) :
equiv.prod_congr (equiv.refl _) (equiv.sum_congr (ih n) (ih (n + 1)))
... ≃ {f // function.surjective f} : s_aux m n
def correctness_2 (m n : nat) : s m n = fintype.card { f : fin m → fin n // function.surjective f } :=
by rw fintype.of_equiv_card (correctness m n); simp
Das erste ist, was wirklich vor sich geht: eine Trennung zwischen [0 ... s(m, n)-1]
und die Auswüchse von [0 ... m-1]
auf [0 ... n-1]
.
Das zweite ist, wie gewöhnlich gesagt wird, das s(m, n)
ist die Kardinalität der Surjektionen von [0 ... m-1]
auf [0 ... n-1]
.
Lean verwendet die Typentheorie als Grundlage (anstelle der Mengenlehre). In der Typentheorie hat jedes Objekt einen Typ, der ihm inhärent ist. nat
ist die Art der natürlichen Zahlen, und die Aussage, dass 0
es sich um eine natürliche Zahl handelt, wird ausgedrückt als 0 : nat
. Wir sagen, das 0
ist von Typ nat
, und das nat
hat 0
als Einwohner.
Sätze (Aussagen / Behauptungen) sind ebenfalls Typen: Ihr Bewohner ist ein Beweis für den Satz.
def
: Wir werden eine Definition einführen (weil eine Bijektion wirklich eine Funktion ist, nicht nur ein Satz).
correctness
: der Name der Definition
∀ m n
: für jedes m
und n
(Lean gibt automatisch an, dass es sich um einen Typ handelt nat
, und zwar aus folgendem Grund).
fin (s m n)
ist die Art der natürlichen Zahlen, die kleiner als ist s m n
. Um einen Einwohner zu machen, liefert man eine natürliche Zahl und einen Beweis, dass sie kleiner ist als s m n
.
A ≃ B
: bijection zwischen dem Typ A
und dem Typ B
. Bijektion zu sagen ist irreführend, da man tatsächlich die Umkehrfunktion bereitstellen muss.
{ f : fin m → fin n // function.surjective f }
die Art der Einwände von fin m
bis fin n
. Diese Syntax bildet einen Untertyp aus dem Typ fin m → fin n
, dh der Art der Funktionen von fin m
bis fin n
. Die Syntax lautet { var : base type // proposition about var }
.
λ m
: ∀ var, proposition / type involving var
ist wirklich eine Funktion, die var
als Eingabe nimmt, also λ m
die Eingabe einführt. ∀ m n,
ist Abkürzung für∀ m, ∀ n,
nat.rec_on m
: Rekursion machen auf m
. Um etwas zu definieren m
, definieren Sie das Ding für 0
und geben Sie das Ding für k
, bauen Sie das Ding für k+1
. Man würde bemerken, dass dies der Induktion ähnlich ist, und dies ist in der Tat ein Ergebnis der Church-Howard-Korrespondenz . Die Syntax lautet nat.rec_on var (thing when var is 0) (for all k, given "thing when k is k", build thing when var is "k+1")
.
Heh, das wird lang und ich bin nur in der dritten Zeile von correctness
...