Lean , 66 byte
def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0
Provalo online!
Prova di correttezza
Provalo online!
Spiegazione
Cerchiamo di annullare la funzione:
def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0 0 := 1
| _ _ := 0
La funzione è definita dal pattern matching e dalla ricorsione, entrambi con supporto integrato.
Definiamo s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)e s(0, 0) = 1, che lascia aperto s(m+1, 0)e s(0, n+1), entrambi definiti 0dall'ultimo caso.
Lean usa la sintassi del calcolo lamdba, così s m nè s(m, n).
Ora, la prova della correttezza: l'ho dichiarata in due modi:
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
Il primo è ciò che sta realmente accadendo: una biiezione tra [0 ... s(m, n)-1]e le sporgenze da [0 ... m-1]sopra [0 ... n-1].
Il secondo è come si dice di solito, cioè s(m, n)la cardinalità delle suriezioni da [0 ... m-1]su [0 ... n-1].
Lean usa la teoria dei tipi come base (invece della teoria dell'insieme). Nella teoria dei tipi, ogni oggetto ha un tipo che è inerente ad esso. natè il tipo di numeri naturali e la frase che 0è un numero naturale è espressa come 0 : nat. Diciamo che 0è di tipo nate che natha 0come abitante.
Le proposizioni (dichiarazioni / asserzioni) sono anche tipi: il loro abitante è una prova della proposizione.
def: Introdurremo una definizione (perché una biiezione è davvero una funzione, non solo una proposizione).
correctness: il nome della definizione
∀ m n: per ogni me n(Lean deduce automaticamente che il loro tipo è nat, a causa di ciò che segue).
fin (s m n)è il tipo di numeri naturali che è inferiore a s m n. Per fare un abitante, si fornisce un numero naturale e una prova che è più piccolo di s m n.
A ≃ B: bijection tra il tipo Ae il tipo B. Dire che la biiezione è fuorviante, in quanto si deve effettivamente fornire la funzione inversa.
{ f : fin m → fin n // function.surjective f }il tipo di sporgenze da fin ma fin n. Questa sintassi crea un sottotipo dal tipo fin m → fin n, ovvero il tipo di funzioni da fin ma fin n. La sintassi è { var : base type // proposition about var }.
λ m: ∀ var, proposition / type involving varè davvero una funzione che accetta varcome input, quindi λ mintroduce l'input. ∀ m n,è una scorciatoia per∀ m, ∀ n,
nat.rec_on m: fare ricorsione su m. Per definire qualcosa per m, definire la cosa per 0e quindi dare la cosa per k, costruire la cosa per k+1. Si noterebbe che questo è simile all'induzione, e in effetti questo è il risultato della corrispondenza Church-Howard . La sintassi è 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, questo sta diventando lungo e sono solo sulla terza linea di correctness...