Lean , 66 bajtów
def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0
Wypróbuj online!
Dowód poprawności
Wypróbuj online!
Wyjaśnienie
Odholfujmy funkcję:
def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0 0 := 1
| _ _ := 0
Funkcja jest zdefiniowana przez dopasowanie wzorca i rekurencję, które mają wbudowane wsparcie.
Definiujemy s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)
i s(0, 0) = 1
, które pozostawiają otwarte, s(m+1, 0)
i s(0, n+1)
oba są zdefiniowane jako 0
ostatni przypadek.
Lean zastosowania składnia lamdba rachunek, tak s m n
jest s(m, n)
.
Teraz dowód poprawności: stwierdziłem to na dwa sposoby:
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
Pierwszym z nich jest to, co się naprawdę dzieje: bijection pomiędzy [0 ... s(m, n)-1]
i przypuszczeniami z [0 ... m-1]
na [0 ... n-1]
.
Drugim jest to, jak zwykle się mówi, to s(m, n)
jest liczebność przypuszczeń z [0 ... m-1]
na [0 ... n-1]
.
Lean używa teorii typów jako podstawy (zamiast teorii mnogości). W teorii typów każdy obiekt ma swój nieodłączny typ. nat
jest rodzajem liczb naturalnych, a wyrażenie, które 0
jest liczbą naturalną, wyraża się jako 0 : nat
. Mówimy, że 0
jest to typowe nat
i nat
ma to 0
jako mieszkaniec.
Twierdzenia (stwierdzenia / twierdzenia) są również typami: ich mieszkaniec jest dowodem zdania.
def
: Wprowadzimy definicję (ponieważ bijection jest tak naprawdę funkcją, a nie tylko propozycją).
correctness
: nazwa definicji
∀ m n
: dla każdego m
i n
(Lean automatycznie wywnioskuje, że ich typ jest nat
, z powodu tego, co następuje).
fin (s m n)
to rodzaj liczb naturalnych, który jest mniejszy niż s m n
. Aby stworzyć mieszkańca, podaje się liczbę naturalną i dowód, że jest ona mniejsza niż s m n
.
A ≃ B
: bijection między typem A
a typem B
. Mówienie bijection jest mylące, ponieważ w rzeczywistości trzeba zapewnić funkcję odwrotną.
{ f : fin m → fin n // function.surjective f }
rodzaj przypuszczeń od fin m
do fin n
. Ta składnia buduje podtyp na podstawie typu fin m → fin n
, tj. Typu funkcji od fin m
do fin n
. Składnia jest następująca { var : base type // proposition about var }
.
λ m
: ∀ var, proposition / type involving var
to tak naprawdę funkcja, która przyjmuje var
dane wejściowe, więc λ m
wprowadza dane wejściowe. ∀ m n,
jest na krótką rękę∀ m, ∀ n,
nat.rec_on m
: wykonaj rekursję w dniu m
. Aby zdefiniować coś dla m
, zdefiniuj rzecz dla, 0
a następnie daj rzecz dla k
, zbuduj rzecz dla k+1
. Można zauważyć, że jest to podobne do indukcji i rzeczywiście jest to wynikiem korespondencji Church-Howard . Składnia jest następująca 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")
.
Hej, robi się to długo i jestem tylko na trzeciej linii correctness
...