Lean , 66 bytes
def s:_->nat->nat|(m+1)(n+1):=(n+1)*(s m n+s m(n+1))|0 0:=1|_ _:=0
Experimente online!
Prova de correção
Experimente online!
Explicação
Vamos desfazer a função:
def s : nat->nat->nat
| (m+1) (n+1) := (n+1)*(s m n + s m (n+1))
| 0 0 := 1
| _ _ := 0
A função é definida pela correspondência e recursão de padrão, ambas com suporte interno.
Definimos s(m+1, n+1) = (n+1) * (s(m, n) + s(m, n+1)e s(0, 0) = 1, que deixa em aberto s(m+1, 0)e s(0, n+1), os quais são definidos como sendo 0no último caso.
O Lean usa a sintaxe do cálculo lamdba, assim s m né s(m, n).
Agora, a prova da correção: afirmei de duas maneiras:
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
O primeiro é o que realmente está acontecendo: uma bijeção entre [0 ... s(m, n)-1]e as exceções de [0 ... m-1]para [0 ... n-1].
O segundo é como é geralmente afirmado, que s(m, n)é a cardinalidade das sobras de [0 ... m-1]para [0 ... n-1].
O Lean usa a teoria dos tipos como base (em vez da teoria dos conjuntos). Na teoria dos tipos, todo objeto tem um tipo que é inerente a ele. naté o tipo de números naturais e a declaração que 0é um número natural é expressa como 0 : nat. Dizemos que 0é do tipo nat, e que nattem 0como habitante.
Proposições (declarações / asserções) também são tipos: seu habitante é uma prova da proposição.
def: Vamos introduzir uma definição (porque uma bijeção é realmente uma função, não apenas uma proposição).
correctness: o nome da definição
∀ m n: for every me n(o Lean deduz automaticamente o seu tipo nat, pelo que se segue).
fin (s m n)é o tipo de números naturais menor que s m n. Para formar um habitante, fornece-se um número natural e uma prova de que é menor que s m n.
A ≃ B: bijeção entre o tipo Ae o tipo B. Dizer bijeção é enganoso, pois é preciso fornecer a função inversa.
{ f : fin m → fin n // function.surjective f }o tipo de rejeições de fin mpara fin n. Essa sintaxe cria um subtipo a partir do tipo fin m → fin n, ou seja, o tipo de funções de fin mpara fin n. A sintaxe é { var : base type // proposition about var }.
λ m: ∀ var, proposition / type involving varé realmente uma função que recebe varcomo entrada, então λ mintroduz a entrada. ∀ m n,é uma mão curta para∀ m, ∀ n,
nat.rec_on m: faça recursão em m. Para definir algo para m, defina a coisa para 0e, em seguida, dê a coisa para k, construa a coisa para k+1. Alguém poderia notar que isso é semelhante à indução e, de fato, isso é resultado da correspondência entre Igreja e Howard . A sintaxe é 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, isso está ficando longo e eu estou apenas na terceira linha de correctness...