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 0
dall'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 nat
e che nat
ha 0
come 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 m
e 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 A
e 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 m
a fin n
. Questa sintassi crea un sottotipo dal tipo fin m → fin n
, ovvero il tipo di funzioni da fin m
a fin n
. La sintassi è { var : base type // proposition about var }
.
λ m
: ∀ var, proposition / type involving var
è davvero una funzione che accetta var
come input, quindi λ m
introduce 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 0
e 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
...